Sonos with node.js, my attempt!


Userlevel 4
Badge +14
INFO

Source code here: https://github.com/jishi/node-sonos-http-api
Sonos Web Controller draft (work in progress!): https://github.com/jishi/node-sonos-web-controller
Sonos IR control (requires lircd and IR reciever): https://github.com/jishi/node-sonos-remote-control

==============================================================


I know that there already is an attempt at this by this guy: http://forums.sonos.com/showthread.php?t=32643, but I found it to be a bit lacking in functionality so I decided to write up my own.

I have created a simple web-based API using what I have, which could be useful for integrating stuff with other applications. This web based API is inspired by other RESTful APIs, however I don't think it follows the correct guidelines to be called a REST API.

IT supports most basic features like:

play, pause, seek, next, prev, volume, mute, setAVTransportURI

It also supports these advanced fatures:

State of player as JSON, zone info as JSON, Play favorite item, presets (grouping, volume, avTransportURI)

You can read more in the README for each project.

To run it as a service under linux, I suggest using pm2 (https://github.com/Unitech/pm2). You need to run it in forked mode (-x)!

For Windows, you might try Winser http://jfromaniello.github.io/winser/

Cheers!

This topic has been closed for further comments. You can use the search bar to find a similar topic, or create a new one by clicking Create Topic at the top of the page.

397 replies

Userlevel 2
No worry Have a good vacation sorry to bother you let me know when your back ...;)
Userlevel 4
Badge +14
Hello,

i like install it on windwos 7 system.

- i have download the node and web zip files.
- i have installed the node this will be fine
- the zip file i have unzipped to a folder
- in cmd i have "npm install" but then i get this logfile

0 info it worked if it ends with ok
1 verbose cli [ 'C:\\Program Files (x86)\\nodejs\\\\node.exe',
1 verbose cli 'C:\\Program Files (x86)\\nodejs\\node_modules\\npm\\bin\\npm-cli.js',
1 verbose cli 'install' ]
2 info using npm@1.3.21
3 info using node@v0.10.24
4 verbose node symlink C:\Program Files (x86)\nodejs\\node.exe
5 error install Couldn't read dependencies
6 error package.json ENOENT, open 'C:\Program Files (x86)\nodejs\package.json'
6 error package.json This is most likely not a problem with npm itself.
6 error package.json npm can't find a package.json file in your current directory.
7 error System Windows_NT 6.1.7601
8 error command "C:\\Program Files (x86)\\nodejs\\\\node.exe" "C:\\Program Files (x86)\\nodejs\\node_modules\\npm\\bin\\npm-cli.js" "install"
9 error cwd C:\Program Files (x86)\nodejs
10 error node -v v0.10.24
11 error npm -v 1.3.21
12 error path C:\Program Files (x86)\nodejs\package.json
13 error code ENOPACKAGEJSON
14 error errno 34
15 verbose exit [ 34, true ]

Can somenoe help me what the error is, what can i do? And how can i install the web controller?

Thanks best regards Thomas


You need to to stand in the unzipped folder before you invoke not install. Not your node folder.
Userlevel 2
Hello,

I want to thank you for taking the time to write provide us with this project.

I was able to install everything and have the node running and able to open up the player in a web browser, however, i have a quick quesetion - how do you invoke the http commands (could you please explain in layman's term?)

Now you can control your system by invoking the following commands:

http://localhost:5005/zones http://localhost:5005/lockvolumes http://localhost:5005/unlockvolumes http://localhost:5005/pauseall[/{timeout in minutes}] http://localhost:5005/resumeall[/{timeout in minutes}] http://localhost:5005/preset/{JSON preset} http://localhost:5005/preset/{predefined preset name} http://localhost:5005/{room name}/{action}[/{parameter}]

Example:

http://localhost:5005/living room/volume/15 (will set volume for room Living Room to 15%)

http://localhost:5005/living room/volume/+1 (will increase volume by 1%)

http://localhost:5005/living room/next (will skip to the next track on living room, unless it's not a coordinator)

http://localhost:5005/living room/pause (will pause the living room)

http://localhost:5005/living room/favorite/mysuperplaylist (will replace queue with the favorite called "mysuperplaylist")

http://localhost:5005/living room/repeat/on (will turn on repeat mode for group)

The actions supported as of today:

play
pause
volume (parameter is absolute or relative volume. Prefix +/- indicates relative volume)
groupVolume (parameter is absolute or relative volume. Prefix +/- indicates relative volume)
mute / unmute
groupMute / groupUnmute
seek (parameter is queue index)
next
previous
state (will return a json-representation of the current state of player)
favorite
lockvolumes / unlockvolumes (experimental, will enforce the volume that was selected when locking!)
repeat (on/off)
shuffle (on/off)
pauseall (with optional timeout in minutes)
resumeall (will resume the ones that was pause on the pauseall call. Useful for doorbell, phone calls, etc. Optional timeout)


Am I supposed to open that as a link in a web browser? My player's room name is called "Living Room" and I'm trying to use the below command:
http://localhost:5005/living room/volume/15

If I paste the above in a web browser, I get a message saying I cannot connect to the server. I've also tried to replace 'localhost' with the server's IP address, same result.

Sorry for the silly question, I'm just looking for ways to automate things from within my phone,
Userlevel 2
Sorry but i didn`t get it to work, when i will install the npm i get some errors...


C:\Program Files (x86)\nodejs>npm install
npm WARN package.json npm@1.3.21 No README data
npm WARN package.json github-url-from-git@1.1.1 No repository field.
npm WARN package.json ronn@0.3.8 'repositories' (plural) Not supported.
npm WARN package.json Please pick one as the 'repository' field

> npm@1.3.21 prepublish C:\Program Files (x86)\nodejs
> node bin/npm-cli.js prune --prefix=. --no-global && rm -rf test/*/*/node_modul
es && make -j32 doc


module.js:340
throw err;
^
Error: Cannot find module 'C:\Program Files (x86)\nodejs\bin\npm-cli.js'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:902:3

npm ERR! npm@1.3.21 prepublish: `node bin/npm-cli.js prune --prefix=. --no-globa
l && rm -rf test/*/*/node_modules && make -j32 doc`
npm ERR! Exit status 8
npm ERR!
npm ERR! Failed at the npm@1.3.21 prepublish script.
npm ERR! This is most likely a problem with the npm package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! node bin/npm-cli.js prune --prefix=. --no-global && rm -rf test/*/*
/node_modules && make -j32 doc
npm ERR! You can get their info via:
npm ERR! npm owner ls npm
npm ERR! There is likely additional logging output above.
npm ERR! System Windows_NT 6.1.7601
npm ERR! command "C:\\Program Files\\nodejs\\\\node.exe" "C:\\Program Files\\nod
ejs\\node_modules\\npm\\bin\\npm-cli.js" "install"
npm ERR! cwd C:\Program Files (x86)\nodejs
npm ERR! node -v v0.10.24
npm ERR! npm -v 1.3.21
npm ERR! code ELIFECYCLE
npm ERR!
npm ERR! Additional logging details can be found in:
npm ERR! C:\Program Files (x86)\nodejs\npm-debug.log
npm ERR! not ok code 0

Who can help me, thanks...
Userlevel 2
Hello,

can i also work with the Janos Web Controller under an Xampp server?

Do i need some other as Xampp?

Thanks, best regards Thomas
Userlevel 2
Jishi,

I wanted to thank you for dedicating the time and effort into this project. I had been searching Hi and Low for a solution that would allow me simple control of my Sonos system (Start Playing a Favorite, Skip Tracks) using my current remote system (a URC MSC400 with several remotes around the house).

I had been using a Sonos plug-in for Homeseer but a whole Win7 PC dedicated for controlling Sonos was overkill.

Thanks to you I now have a Raspberry Pi that I shoehorned into an empty Sonos Bridge. It required some modification but it just barely fits inside. I also placed an IR transmitter inside the case so it looks like a nice clean finished component. Just power, ir wire and a network cable out of the back of the bridge.

Using the process described here: http://blog.rueedlinger.ch/2013/03/raspberry-pi-and-nodejs-basic-setup/ The RPi will boot and run your remote control node script.

Its been working great for controlling Sonos via IR commands

I have a couple of questions about issuing play commands and setting up direct control over zones (trying to avoid using the player.cordinator) but for the moment I just wanted to say thank you!
Userlevel 2
A open request :

I am trying as I am not really a programmer ....

To add a group of functions to play a tts mp3 file.

Logic:
Scan whole system remember the state of the system whats playing vol mute unmute etc.

then create a mp3 file format from text file add it to the Que then play that file based on a preset created then return the system back to orig state.

This could be used as a weather alert system doorbell anything that may come across even text messages. from your cell . I want to set it up with my Google calender

Anyone interested in creating this?

Regards

Robert
Userlevel 4
Badge +14
Hello,

I want to thank you for taking the time to write provide us with this project.

I was able to install everything and have the node running and able to open up the player in a web browser, however, i have a quick quesetion - how do you invoke the http commands (could you please explain in layman's term?)


The HTTP commands are a separate component than the web controller. You can run them at the same time, even using the same backend, but that requires some modifications to the files. The preferred way is to extend the web controller with the http api, but it will be harder to maintain atm. I might distribute a zip with them both active, for those who wants to use it.
Userlevel 4
Badge +14
Hello,

can i also work with the Janos Web Controller under an Xampp server?

Do i need some other as Xampp?

Thanks, best regards Thomas


I don't know what you want to achieve. My implementation is completely standalone and doesn't require anything else than node.js. Don't confuse it with the Janos application.

Look at the first post, I have updated it with a downloadable link with all dependencies already met. You just unzip it to a folder and start it with:

node server.js

And you should be good to go.
Userlevel 2
Jishi
Thanks to you I now have a Raspberry Pi that I shoehorned into an empty Sonos Bridge. It required some modification but it just barely fits inside. I also placed an IR transmitter inside the case so it looks like a nice clean finished component. Just power, ir wire and a network cable out of the back of the bridge.


Hi Nice solution with the Raspberry Pi in a Bridge box. I have think to do the same but just run the Rasberry Pi unboxed so far.
But I love to just use my spare Apple TV remote to pause/change volum then the phone ring.
This is a thing that Sonos totally have missed to mount a simple IR recivier in all Sonos speakers.

And agin great work Jishi!
Userlevel 2
Hello,

nice work. I already use your http api on my raspi.

2 Questions:

Is it possible to seek in a track? Go to a specific time on the current track?

Is it possible to change the queue with a favorite but not start playing.

What i want to do in my python program is:
  • favorite A is playing.
  • get an event (buttonpress e.g.)
  • Save the current state of the track. (where the queue is based on favorite A)
  • Change the queue with a favorite B.
  • Start playing favorite B.
  • get an event (buttonpress e.g.)
  • Switching back to favorite A. Start playing from the track and position which was saved in the first step.



Third Question:
Is it possible to get more information on the favorites? If it is a Radio Station or a List?

thx
Userlevel 4
Badge +14
Hello,

nice work. I already use your http api on my raspi.

2 Questions:

Is it possible to seek in a track? Go to a specific time on the current track?

Is it possible to change the queue with a favorite but not start playing.

What i want to do in my python program is:
  • favorite A is playing.
  • get an event (buttonpress e.g.)
  • Save the current state of the track. (where the queue is based on favorite A)
  • Change the queue with a favorite B.
  • Start playing favorite B.
  • get an event (buttonpress e.g.)
  • Switching back to favorite A. Start playing from the track and position which was saved in the first step.



Third Question:
Is it possible to get more information on the favorites? If it is a Radio Station or a List?

thx


Hi. I have implemented trackSeek in the discovery-library (mainly for the web controller), so it would be easy enough to add it to the http api as well. It takes elapsed time in seconds, but it would be possible to add some sort of parsing as well if that is needed ("0:05" instead of just 5, "1:04" instead of 64).

Your second question, regarding switching between favorites. It would be possible, but note that you can not know which favorite that is playing (unless you store it yourself, and only control it using your python script). Are you planning on using a regular keyboard? If you are familiar with js, I have an example here: http://upload.grabbarna.se/files/keyboard.js

That way, you wouldn't need to work through the HTTP API but instead speak directly with the sonos-component in node.js, meaning that you can run it inside the http api.

3. I think there might be info if it is a playlist or a radio, otherwise you can work it out from the uri. There are only a few prefixes that are for radio, the once I have identified is:

code:

if (item.uri.startsWith("x-sonosapi-stream:") || item.uri.startsWith("x-sonosapi-radio:") || item.uri.startsWith("pndrradio:")) {
Userlevel 2
Thanks for you answers!

It would be nice if you can implement the trackseek in the http-api. As your api delivers both, it's not important for me if there is a parsing or not.
I am experimenting with python and hacked a little script for the raspberry GPIOs with a button (my event which triggers the switch of the favorites) and a bunch of LEDs.
So for this i need python (cause i didn't find a propper nodejs-api) and your http api comes right in, because making requests is very easy in python.
My python script keeps track of which favorite is currently playing.

For the favorites with the http-api: so i get with "favorites" all favorites titles and then with "favorite/..title..." get the uri and filter all favorites with the proper uri to get only radio-favorites? Is that correct? Or is there a simpler solution?
But for this i have the problem that a favorite starts playing immediat.

Crap 😉 ... no good nodejs raspberry-gpio api yet, and no good python api for sonos which supports favorites yet.
Userlevel 4
Badge +14

For the favorites with the http-api: so i get with "favorites" all favorites titles and then with "favorite/..title..." get the uri and filter all favorites with the proper uri to get only radio-favorites? Is that correct? Or is there a simpler solution?
But for this i have the problem that a favorite starts playing immediat.


Well, for now you will need to check the uri to make the distinction. I will see if I can extract more info about it, but it's possible that it will just say "Spotify playlist" "Itunes radio" and stuff like that...

The reason that it starts immediately is because the http api will send play after a successful invokation, see row 217 in https://github.com/jishi/node-sonos-http-api/blob/master/lib/sonos-http-api.js:

code:

case "favorite":
player.coordinator.replaceWithFavorite(options.value, function (success) {
if (success)
player.coordinator.play();
});


You could just remove that, or if you come up with a way to make it selectable or configurable. Do you want different behavior on different favorites, or different behavior permanently?
Userlevel 2
I have a question about using the favorites command in your sonos-ir-control script.

I have little programming experience and none in Javascript so please forgive my simple questions. This is also the first time I've used a Raspberry Pi and the closest thing I've used to Linux was Unix and that was ~15 years ago.

I have modified your sonos-IR-Control.js file to map to my IR commands. To execute playlist commands I use the following:

"KEY_3": function (player) {
player.coordinator.replaceWithFavorite("162.4 | NOAA Weather Radio (Weather)");
player.coordinator.play();
return true;
},

I have tried copying the replaceWithFavorite command from your http-api but had issues getting "success" part of the function to work.

As a result I added the play command after the favorite command, but for certain favorites the timing is off and the play command is sent too early and missed.

If you have the time and patience could you help me get the replacewithfavorite command into the remote-IR script?

Thanks
Userlevel 4
Badge +14


"KEY_3": function (player) {
player.coordinator.replaceWithFavorite("162.4 | NOAA Weather Radio (Weather)");
player.coordinator.play();
return true;
},


Hi, it takes some time to get comfortable with the asynchronous execution model that you use in this case.

The .replaceWithFavorite(string favoriteName, function callback) takes two arguments, where the latter is a function declaration. this function will be invoked when the execution is done, and that is where you need to invoke the play command.

So:

code:

"KEY_3": function (player) {
player.coordinator.replaceWithFavorite("162.4 | NOAA Weather Radio (Weather)", function (success) {
if (success) player.coordinator.play();
});
return true;
},


Also, the callback will get 1 argument which is true/false depending on if the invokation was successful or not.
Userlevel 2
Perfect! Works great.

Previously I had tried copying the function directly out of your http-api and it threw errors when I ran the script via node. Not sure what I did but I messed up somewhere.

This works great, Thanks!
Userlevel 4
Badge +14

It would be nice if you can implement the trackseek in the http-api.


I pushed an update to the git repo with "trackseek" implemented. It will take total seconds that you want to seek into (for 2:00):

/Office/trackseek/120
Userlevel 2
I pushed an update to the git repo with "trackseek" implemented. It will take total seconds that you want to seek into (for 2:00):

/Office/trackseek/120



nice thx
Userlevel 4
Badge +14
Hi guys.

I remember reading somewhere that somebody wanted the LED state of the players to be on when something was playing, and off when the player was paused/stopped.

Realized that isn't such a hard thing to accomplish, so I did a quick function for it.

Doing something like this:

code:

var SonosDiscovery = require('sonos-discovery');
var discovery = new SonosDiscovery();
discovery.setToggleLED(true);


Unfortunately there is a bit of delay (1s or something). I think someone wanted it for a light sensor that would power on/off an amplifier. I thought it was a fun feature anyway, even if nobody finds it useful 🙂
Userlevel 2
Jishi,
first of all - a great piece of work.

I have spent the whole day installing it (both web controller and API) on my RASPI and in the final step come across a problem when trying to run it in the background.

I have tried using both FOREVER and PM2 to start the processes during boot time. This it does quite happily with no errors shown in the log files.

The problem that I observe however is that the web client wont display in a browser if the process is started with FOREVER (or PM2 when the -x option is used).

PM2 works if the mode is cluster - however this then eats 100% CPU.

The log file contents are identical when starting in the background or when starting from a terminal window. It indicates no errors or warnings.

The browser doesn't complain that the website is not there - it just sits and waits and displays nothing.

Anyone have any ideas?

I'm using the latest versions of everything (node 0.10.2) and the sonos-web-controller_0.6.0_pi build.

Peter
Userlevel 4
Badge +14
Jishi,
first of all - a great piece of work.

I have spent the whole day installing it (both web controller and API) on my RASPI and in the final step come across a problem when trying to run it in the background.

I have tried using both FOREVER and PM2 to start the processes during boot time. This it does quite happily with no errors shown in the log files.

The problem that I observe however is that the web client wont display in a browser if the process is started with FOREVER (or PM2 when the -x option is used).

PM2 works if the mode is cluster - however this then eats 100% CPU.

The log file contents are identical when starting in the background or when starting from a terminal window. It indicates no errors or warnings.

The browser doesn't complain that the website is not there - it just sits and waits and displays nothing.

Anyone have any ideas?

I'm using the latest versions of everything (node 0.10.2) and the sonos-web-controller_0.6.0_pi build.

Peter


Hm, that is odd. I just tried it out and it works on my raspberry. I do however run it as root, which you might not.

What does the output from "netstat -ntpl" say? What OS are you running? Rasbian? Which port are you trying to run it under?

And, does it work, if you run it directly from the shell? Even as the same user that pm2 will run under?
Userlevel 2
so everything is running as root (I'm lazy 🙂 )

If I do not use PM2 or FOREVER and run directly from the terminal window in x-windows then it works.

Run under PM2 from the terminal window in clustered mode it works.

Run under PM2 from the terminal window in forked mode it doesn't work.

The api program works without problem. It's just the web controller that has issues. The web browser seems to be connecting but just not receiving data (it doesn't even timeout??) have tried with Chrome and Firefox.
Have even tried with only starting the web controller and leaving the api down - but I really want to use both.

OS is RASPIDAN

Port settings are all the defaults - I have not changed any of your settings


UPDATE::::::
Tried it again this morning and PM2 works!!!!
FOREVER still doesn't work but if PM2 is working I'm happy. The only thing that I can think of that I had changed in the mean time was to put the node and application paths into the PATH statement in the etc/.profile
Userlevel 4
Badge +14
Make sure that it is running in forked mode. If you started under cluster mode, then stopped it, and started it again with -x (without deleting it from pm2) it will still start in cluster mode.

Also, did you fix the startup script for pm2? (pm2 startup) That should fix environment variables, and then you should start pm2 using the init.d script.
Userlevel 2
Yep did all that :)

As I said, suddenly started working this morning.