Project tutorial
Control Your SONOS with Arduino and NODE-RED

Control Your SONOS with Arduino and NODE-RED

Start radio stations with buttons on your Arduino and play it over SONOS. NODE-RED on a Raspberry Pi receives http-posts and controls SONOS.

  • 2,491 views
  • 0 comments
  • 2 respects

Components and supplies

About this project

My first solution to control my SONOS system was Arduino and IFTTT.

After IFTTT is no longer free, I searched for an alternative. NODE-RED is a big tool to wire online-services, hardware etc. together. It has has lots of features and is easy to install on a Raspberry Pi. There are also extensions (palettes) for SONOS.

The only difficult part was to get the HTTP-POSTs from ARDUINO to NODE-RED, but with a simple http-endpoint node the job was done quickly.

Code

arduino codeArduino
code for buttons and communication to node red
#include <SPI.h>
#include <WiFiNINA.h>
#include <ArduinoHttpClient.h>

// for NANO 33 IoT

const int button_1 = 2; // digital pin 2 ...
const int button_2 = 3;
const int button_3 = 4;
const int button_4 = 5;
const int button_5 = 6;
const int button_6 = 7;
const int ledPin = LED_BUILTIN; // pin to use for the LED

char ssid[] = "";     //  your network SSID (name)
char pass[] = "";  // your network password

const int station_array_size = 3;

// string array is station_name, station_url, station_image (does not work :-(  )
String oe1[station_array_size] = { "Österreich 1", "mp3stream3.apasf.apa.at%3A8000", "" };
String soho_radio[station_array_size] = { "Soho Radio", "https://sohoradiomusic.doughunt.co.uk:8010/320mp3", "" };
String latte_miele[station_array_size] = { "Latte Miele", "playerservices.streamtheworld.com/api/livestream-redirect/LATTEMIELE.mp3", "" };
String bbc6[station_array_size] = { "BBC 6 Music", "http://a.files.bbci.co.uk/media/live/manifesto/audio/simulcast/hls/nonuk/sbr_low/llnw/bbc_radio_two.m3u8", "" };
String dlf[station_array_size] = { "Deutschlandfunk", "https://st01.sslstream.dlf.de/dlf/01/128/mp3/stream.mp3", "" };

int status = WL_IDLE_STATUS;
char server[] = "192.168.0.87"; // raspberry pi with node-red
String endpoint_sonos_play_radio = "/sonos_play_radio";
String endpoint_sonos = "/sonos";

int port = 1880;

WiFiClient wifi;

HttpClient client = HttpClient(wifi, server, port);


void setup() {
  Serial.begin(9600);

  // set LED pin to output mode
  pinMode(ledPin, OUTPUT);

  // configure the button pin as input
  pinMode(button_1, INPUT);
  pinMode(button_2, INPUT);
  pinMode(button_3, INPUT);
  pinMode(button_4, INPUT);
  pinMode(button_5, INPUT);
  pinMode(button_6, INPUT);
  digitalWrite(button_1, HIGH);
  digitalWrite(button_2, HIGH);
  digitalWrite(button_3, HIGH);
  digitalWrite(button_4, HIGH);
  digitalWrite(button_5, HIGH);
  digitalWrite(button_6, HIGH);

  // check for the WiFi module:
  if (WiFi.status() == WL_NO_MODULE) {
    Serial.println("Communication with WiFi module failed!");
    // don't continue
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv < WIFI_FIRMWARE_LATEST_VERSION) {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(7000);
  }
  Serial.println("Connected to wifi");
  printWifiStatus();
  Serial.println();
}

void loop() {
  digitalWrite(ledPin, LOW);

  if (digitalRead(button_1) == 0) {
    Serial.println("button 1 pressed");
    digitalWrite(ledPin, HIGH);
    web_request(endpoint_sonos_play_radio, oe1[0]);
  }
  if (digitalRead(button_2) == 0) {
    Serial.println("button 2 pressed");
    digitalWrite(ledPin, HIGH);
    web_request(endpoint_sonos_play_radio, soho_radio[0]);
  }
  if (digitalRead(button_3) == 0) {
    Serial.println("button 3 pressed");
    digitalWrite(ledPin, HIGH);
    web_request(endpoint_sonos_play_radio, latte_miele[0]);
  }
  if (digitalRead(button_4) == 0) {
    Serial.println("button 4 pressed");
    digitalWrite(ledPin, HIGH);
    web_request(endpoint_sonos_play_radio, bbc6[0]);
  }
  if (digitalRead(button_5) == 0) {
    Serial.println("button 5 pressed");
    digitalWrite(ledPin, HIGH);
    web_request(endpoint_sonos_play_radio, dlf[0]);
  }
  if (digitalRead(button_6) == 0) {
    Serial.println("button 6 pressed");
    digitalWrite(ledPin, HIGH);
    web_request(endpoint_sonos, "stop");
  }
//  while (client.available()) {
//    char c = client.read();
//    Serial.write(c);
//  }
}

// body is POST-body message
// path is http-endpoint eg. /sonos_play_radio, /sonos
void web_request(String path, String body) {
  Serial.println("making POST request with:");
  String contentType = "text/plain";
  Serial.println(body);

  client.post(path, contentType, body);
  //client.get("/");

  // read the status code and body of the response
  int statusCode = client.responseStatusCode();
  String response = client.responseBody();
  
  Serial.print("Status code: ");
  Serial.println(statusCode);
  Serial.print("Response: ");
  Serial.println(response);
  Serial.println();
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}
node-red flowJSON
[{"id":"49b1e0b1.19c7c","type":"tab","label":"sonos","disabled":false,"info":""},{"id":"6ee5c211.a3e94c","type":"comment","z":"49b1e0b1.19c7c","name":"hear radio in group","info":"","x":110,"y":40,"wires":[]},{"id":"103843b4.962a64","type":"inject","z":"49b1e0b1.19c7c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Soho Radio","payloadType":"str","x":110,"y":100,"wires":[["20e2177b.99bce8"]]},{"id":"5e8ea9f7.de104","type":"inject","z":"49b1e0b1.19c7c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"BBC Radio 6 Music","payloadType":"str","x":130,"y":140,"wires":[["20e2177b.99bce8"]]},{"id":"7d65fe13.55bd3","type":"sonos-universal","z":"49b1e0b1.19c7c","confignode":"631c3eea.24d26","compatibilityMode":false,"command":"group.play","state":"","stateType":"str","name":"","x":590,"y":180,"wires":[["68e99155.d7b4"]]},{"id":"68e99155.d7b4","type":"debug","z":"49b1e0b1.19c7c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":690,"y":480,"wires":[]},{"id":"20e2177b.99bce8","type":"sonos-manage-mysonos","z":"49b1e0b1.19c7c","confignode":"631c3eea.24d26","compatibilityMode":false,"command":"mysonos.stream.item","state":"","stateType":"str","name":"","x":380,"y":180,"wires":[["7d65fe13.55bd3"]]},{"id":"318ffa9c.4ed80e","type":"inject","z":"49b1e0b1.19c7c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Österreich 1","payloadType":"str","x":110,"y":180,"wires":[["20e2177b.99bce8"]]},{"id":"7aeee122.f02b1","type":"inject","z":"49b1e0b1.19c7c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Latte Miele","payloadType":"str","x":100,"y":220,"wires":[["20e2177b.99bce8"]]},{"id":"8b8f95d2.fd20f8","type":"inject","z":"49b1e0b1.19c7c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"Deutschlandfunk","payloadType":"str","x":120,"y":260,"wires":[["20e2177b.99bce8"]]},{"id":"a8e0b53.be01348","type":"http in","z":"49b1e0b1.19c7c","name":"","url":"/sonos_play_radio","method":"post","upload":false,"swaggerDoc":"","x":130,"y":440,"wires":[["e8814bd7.cfdc7","c1ff38e4.c09fc8","20e2177b.99bce8"]]},{"id":"e8814bd7.cfdc7","type":"template","z":"49b1e0b1.19c7c","name":"page","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"<html>\n    <head></head>\n    <body>\n        <h1>Hello {{ payload }}!</h1>\n    </body>\n</html>","x":330,"y":440,"wires":[["c7479080.523148"]]},{"id":"c7479080.523148","type":"http response","z":"49b1e0b1.19c7c","name":"","x":470,"y":440,"wires":[]},{"id":"47cb864c.f3ce08","type":"comment","z":"49b1e0b1.19c7c","name":"example urls","info":"curl -X POST -d 'Soho Radio' -H \"Content-type: text/plain\" http://192.168.0.87:1880/sonos_play_radio\n\ncurl -X POST -d 'Deutschlandfunk' -H \"Content-type: text/plain\" http://192.168.0.87:1880/sonos_play_radio\n\n","x":90,"y":400,"wires":[]},{"id":"c1ff38e4.c09fc8","type":"debug","z":"49b1e0b1.19c7c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":330,"y":480,"wires":[]},{"id":"5bd7b3a0.287e3c","type":"sonos-universal","z":"49b1e0b1.19c7c","confignode":"631c3eea.24d26","compatibilityMode":false,"command":"group.stop","state":"","stateType":"str","name":"","x":530,"y":660,"wires":[["68e99155.d7b4"]]},{"id":"71786316.bd9c4c","type":"inject","z":"49b1e0b1.19c7c","name":"stop","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"str","x":330,"y":640,"wires":[["5bd7b3a0.287e3c"]]},{"id":"dc8e0e59.44e2e","type":"http in","z":"49b1e0b1.19c7c","name":"","url":"/sonos","method":"post","upload":false,"swaggerDoc":"","x":90,"y":720,"wires":[["37bc1097.7da67","e8814bd7.cfdc7"]]},{"id":"37bc1097.7da67","type":"switch","z":"49b1e0b1.19c7c","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"stop","vt":"str"},{"t":"eq","v":"play","vt":"str"},{"t":"eq","v":"pause","vt":"str"}],"checkall":"true","repair":false,"outputs":3,"x":320,"y":720,"wires":[["5bd7b3a0.287e3c"],["3ef330ef.4298d8"],["9946d885.512f18"]]},{"id":"3ef330ef.4298d8","type":"sonos-universal","z":"49b1e0b1.19c7c","confignode":"631c3eea.24d26","compatibilityMode":false,"command":"group.play","state":"","stateType":"str","name":"","x":530,"y":720,"wires":[["68e99155.d7b4"]]},{"id":"9946d885.512f18","type":"sonos-universal","z":"49b1e0b1.19c7c","confignode":"631c3eea.24d26","compatibilityMode":false,"command":"group.pause","state":"","stateType":"str","name":"","x":530,"y":780,"wires":[["68e99155.d7b4"]]},{"id":"8b3dc05.24f064","type":"sonos-universal","z":"49b1e0b1.19c7c","confignode":"631c3eea.24d26","compatibilityMode":false,"command":"group.get.trackplus","state":"","stateType":"str","name":"","x":370,"y":940,"wires":[["d1cb0e93.ff078"]]},{"id":"f0a303d0.1dc938","type":"comment","z":"49b1e0b1.19c7c","name":"stop, play or pause the group","info":"","x":140,"y":600,"wires":[]},{"id":"8b74c1c5.06c1a8","type":"inject","z":"49b1e0b1.19c7c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"","payloadType":"date","x":90,"y":940,"wires":[["8b3dc05.24f064"]]},{"id":"d1cb0e93.ff078","type":"debug","z":"49b1e0b1.19c7c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":590,"y":940,"wires":[]},{"id":"d9b364cf.523d","type":"comment","z":"49b1e0b1.19c7c","name":"get infos","info":"","x":90,"y":900,"wires":[]},{"id":"2d2a91b.60f7eee","type":"sonos-universal","z":"49b1e0b1.19c7c","confignode":"631c3eea.24d26","compatibilityMode":false,"command":"group.set.volume","state":"","stateType":"str","name":"","x":370,"y":1040,"wires":[["859572ff.f724f8"]]},{"id":"5347976e.45ef1","type":"inject","z":"49b1e0b1.19c7c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"1","payloadType":"num","x":90,"y":1040,"wires":[["2d2a91b.60f7eee"]]},{"id":"859572ff.f724f8","type":"debug","z":"49b1e0b1.19c7c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","statusVal":"","statusType":"auto","x":590,"y":1040,"wires":[]},{"id":"78b7a900.06d57","type":"inject","z":"49b1e0b1.19c7c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"5","payloadType":"num","x":90,"y":1080,"wires":[["2d2a91b.60f7eee"]]},{"id":"83655f37.e7a628","type":"inject","z":"49b1e0b1.19c7c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"10","payloadType":"num","x":90,"y":1120,"wires":[["2d2a91b.60f7eee"]]},{"id":"9f262918.41c9f8","type":"inject","z":"49b1e0b1.19c7c","name":"","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","payload":"15","payloadType":"num","x":90,"y":1160,"wires":[["2d2a91b.60f7eee"]]},{"id":"631c3eea.24d26","type":"sonos-config","z":"","name":"Küche","serialnum":"","ipaddress":"192.168.0.192"}]

Schematics

switches with arduino
8170c1b8 10ac 417f 9f7f ea25ed7e6c05 1 201 a mj6iudc4fg

Comments

Similar projects you might like

Servo Control with TV Remote Control

Project showcase by eldo85

  • 26,102 views
  • 8 comments
  • 48 respects

Control the Speed of Brushless DC Motor Using Bluetooth

Project tutorial by mohitmehlawat

  • 15,757 views
  • 3 comments
  • 24 respects

Control Two Relays Over the Internet

Project tutorial by Arduino_Genuino

  • 7,298 views
  • 1 comment
  • 4 respects

Speak to Arduino and Control It with Google Assistant

Project tutorial by ElectroPeak

  • 86,994 views
  • 30 comments
  • 199 respects

Enable Alexa Control to your Ceiling Fan

Project tutorial by Jithin Thulase

  • 6,957 views
  • 5 comments
  • 11 respects
Add projectSign up / Login