This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
int LED = D1; | |
int PR = A0; // photoresistor port | |
int BUTTON = D0; // button port | |
bool bright; | |
bool pressed; | |
bool playing; | |
int brightness = 0; // to store the current brightness | |
// Sonos stuff grabbed from Hover_particle | |
// Set to IP of your Sonos player | |
byte sonosip[] = { 192, 168, 0, 217 }; | |
#define SOAP_HEADER "<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body>" | |
#define SOAP_FOOTER "</s:Body></s:Envelope>\r\n" | |
#define SONOS_PAUSE "<u:Pause xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>0</InstanceID></u:Pause>" | |
#define SONOS_PLAY "<u:Play xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>0</InstanceID><Speed>1</Speed></u:Play>" | |
#define SONOS_NEXT "<u:Next xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>0</InstanceID></u:Next>" | |
#define SONOS_PREVIOUS "<u:Previous xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>0</InstanceID></u:Previous>" | |
#define SONOS_SETVOLUME_HEADER "<u:SetVolume xmlns:u=\"urn:schemas-upnp-org:service:RenderingControl:1\"><InstanceID>0</InstanceID><Channel>Master</Channel><DesiredVolume>" | |
#define SONOS_SETVOLUME_FOOTER "</DesiredVolume></u:SetVolume></s:Body></s:Envelope>" | |
#define SONOS_TRANSPORT_INFO "<u:GetPositionInfo xmlns:u=\"urn:schemas-upnp-org:service:AVTransport:1\"><InstanceID>0</InstanceID></u:GetPositionInfo>" | |
#define SONOS_GETVOLUME "<u:GetVolume xmlns:u=\"urn:schemas-upnp-org:service:RenderingControl:1\"><InstanceID>0</InstanceID><Channel>Master</Channel></u:GetVolume>" | |
#define PAUSE 0 | |
#define PLAY 1 | |
#define NEXT 2 | |
#define PREVIOUS 3 | |
#define VOLUME 4 | |
#define TRANSPORTINFO 5 | |
#define GETVOLUME 6 | |
TCPClient client; | |
unsigned long timeout; | |
int sonosVolume; | |
char songTitle[32]; | |
char songArtist[32]; | |
char songVolume[12]; | |
void setup() { | |
pinMode(LED, OUTPUT); | |
pinMode(PR, INPUT); | |
pinMode(BUTTON, INPUT); | |
digitalWrite(LED, LOW); | |
//check environment and set bright accordingly | |
if(analogRead(PR)>=2000) bright=true; | |
else bright=false; | |
//set pressed state | |
if(digitalRead(BUTTON)==HIGH) pressed=true; | |
else pressed=false; | |
Particle.function("led", ledToggler); | |
Particle.variable("brightness", &brightness, INT); | |
//pause Sonos | |
playing=false; | |
sonos(PAUSE); | |
} | |
void loop() { | |
brightness=analogRead(PR); | |
if(digitalRead(BUTTON)==HIGH && !pressed) { | |
Particle.publish("button pressed", NULL); | |
pressed=true; | |
// toggle between PLAY and PAUSE when button is pressed | |
if(!playing) { | |
sonos(PLAY); | |
playing=true; | |
} else { | |
sonos(PAUSE); | |
playing=false; | |
} | |
} else if(digitalRead(BUTTON)==LOW && pressed) { | |
pressed=false; | |
} | |
if(brightness >= 2000 && !bright) { | |
Particle.publish("lights on", String(brightness), 60, PRIVATE); | |
bright=true; | |
} | |
else if(brightness < 2000 && bright) { | |
Particle.publish("lights out", String(brightness), 60, PRIVATE); | |
bright=false; | |
} | |
delay(1000); | |
} | |
int ledToggler(String command) { | |
if(command=="on") { | |
digitalWrite(LED, HIGH); | |
return 1; | |
} | |
else if(command=="off") { | |
digitalWrite(LED, LOW); | |
return 0; | |
} | |
else | |
{ | |
return -1; | |
} | |
} | |
void out(const char *s) | |
{ | |
client.write( (const uint8_t*)s, strlen(s) ); | |
} | |
void sonos(int cmd) | |
{ | |
char buf[512]; | |
char soapmsg[1024]; | |
char cmdtag[20]; | |
sonosVolume = 35; | |
if (client.connect(sonosip, 1400)) { | |
switch (cmd) { | |
case PAUSE: | |
sprintf(soapmsg, "%s%s%s", SOAP_HEADER, SONOS_PAUSE, SOAP_FOOTER); | |
strcpy(cmdtag, "Pause"); | |
break; | |
case PLAY: | |
sprintf(soapmsg, "%s%s%s", SOAP_HEADER, SONOS_PLAY, SOAP_FOOTER); | |
strcpy(cmdtag, "Play"); | |
break; | |
case NEXT: | |
sprintf(soapmsg, "%s%s%s", SOAP_HEADER, SONOS_NEXT, SOAP_FOOTER); | |
strcpy(cmdtag, "Next"); | |
break; | |
case PREVIOUS: | |
sprintf(soapmsg, "%s%s%s", SOAP_HEADER, SONOS_PREVIOUS, SOAP_FOOTER); | |
strcpy(cmdtag, "Previous"); | |
break; | |
case VOLUME: | |
sprintf(soapmsg, "%s%s%i%s", SOAP_HEADER, SONOS_SETVOLUME_HEADER, sonosVolume, SONOS_SETVOLUME_FOOTER); | |
strcpy(cmdtag, "SetVolume"); | |
break; | |
case TRANSPORTINFO: | |
sprintf(soapmsg, "%s%s%s", SOAP_HEADER, SONOS_TRANSPORT_INFO, SOAP_FOOTER); | |
strcpy(cmdtag, "GetPositionInfo"); | |
break; | |
case GETVOLUME: | |
sprintf(soapmsg, "%s%s%s", SOAP_HEADER, SONOS_GETVOLUME, SOAP_FOOTER); | |
strcpy(cmdtag, "GetVolume"); | |
break; | |
} | |
if (String(cmdtag) == "SetVolume" || String(cmdtag) == "GetVolume") { | |
out("POST /MediaRenderer/RenderingControl/Control HTTP/1.1\r\n"); | |
} else { | |
out("POST /MediaRenderer/AVTransport/Control HTTP/1.1\r\n"); | |
} | |
sprintf(buf, "Host: %d.%d.%d.%d:1400\r\n", sonosip[0], sonosip[1], sonosip[2], sonosip[3]); | |
out(buf); | |
sprintf(buf, "Content-Length: %d\r\n", strlen(soapmsg)); | |
out(buf); | |
out("Content-Type: text/xml; charset=\"utf-8\"\r\n"); | |
if (String(cmdtag) == "SetVolume" || String(cmdtag) == "GetVolume") { | |
sprintf(buf, "Soapaction: \"urn:schemas-upnp-org:service:RenderingControl:1#%s\"\r\n", cmdtag); | |
} else { | |
sprintf(buf, "Soapaction: \"urn:schemas-upnp-org:service:AVTransport:1#%s\"\r\n", cmdtag); | |
} | |
out(buf); | |
out("\r\n"); | |
out(soapmsg); | |
/*wait 1s for timeout*/ | |
timeout = millis(); | |
while ((!client.available()) && ((millis() - timeout) < 1000)); | |
int i = 0; | |
char sonosResponse[3072]; | |
while (client.available()) { | |
char c = client.read(); | |
Serial.print(c); | |
if (String(cmdtag) == "GetPositionInfo" || String(cmdtag) == "GetVolume") { | |
sonosResponse[i] = c; | |
Serial.print(sonosResponse[i]); //This line prints the entire response | |
i++; | |
} | |
} | |
if (String(cmdtag) == "GetPositionInfo") { | |
sonosResponse[i] = '\0'; | |
/* Get the song title */ | |
char *p1 = strcasestr(sonosResponse,"dc:title>"); | |
char *p2 = strcasestr(sonosResponse,"</dc:title"); | |
int c = 0; | |
for (p1 = p1 + 12; p1 != p2; p1++) { | |
songTitle[c] = *p1; | |
c++; | |
} | |
songTitle[c] = '\0'; | |
Serial.println(songTitle); | |
/* Get the Artist */ | |
p1 = strcasestr(sonosResponse,"dc:creator>"); | |
p2 = strcasestr(sonosResponse,"</dc:creator"); | |
c = 0; | |
for (p1 = p1 + 14; p1 != p2; p1++) { | |
songArtist[c] = *p1; | |
c++; | |
} | |
songArtist[c] = '\0'; | |
Serial.println(songArtist); | |
/* Get the Album */ | |
/*p1 = strcasestr(sonosResponse,";upnp:album>"); | |
p2 = strcasestr(sonosResponse,"</upnp:album>"); | |
c = 0; | |
for (p1 = p1 + 15; p1 != p2; p1++) { | |
songAlbum[c] = *p1; | |
c++; | |
} | |
songAlbum[c] = '\0'; | |
Serial.println(songAlbum);*/ | |
} else if (String(cmdtag) == "GetVolume") { | |
sonosResponse[i] = '\0'; | |
char *p1 = strcasestr(sonosResponse,"<CurrentVolume>"); | |
char *p2 = strcasestr(sonosResponse,"</CurrentVolume>"); | |
int c = 0; | |
for (p1 = p1 + 15; p1 != p2; p1++) { | |
songVolume[c] = *p1; | |
c++; | |
} | |
songVolume[c] = '\0'; | |
Serial.println(songVolume); | |
sscanf(songVolume, "%d", &sonosVolume); | |
Serial.println(sonosVolume); | |
} | |
//while (client.available()) client.read(); | |
//delay(100); | |
client.stop(); | |
} else { | |
Serial.println("Not yet connected to Sonos."); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
TCPClient client; error