hatschibratschimobile
Published

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.

IntermediateFull instructions provided4,020
Control Your SONOS with Arduino and NODE-RED

Things used in this project

Hardware components

Raspberry Pi 3 Model B
Raspberry Pi 3 Model B
×1
Tactile Switch, Top Actuated
Tactile Switch, Top Actuated
×6
Jumper wires (generic)
Jumper wires (generic)
×1

Hand tools and fabrication machines

Arduino nano board 33 IOT
Arduino nano board 33 IOT

Story

Read more

Schematics

switches with arduino

Code

arduino code

Arduino
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 flow

JSON
[{"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"}]

Credits

hatschibratschimobile
2 projects • 0 followers

Comments