Skip to main content
Headliner II
March 5, 2013

Sonos with node.js, my attempt!

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.

    391 replies

    Lyricist III
    January 3, 2015
    Hi Jishi,

    I have been using your excellent Sonos-lirc module running on a Raspberry Pi for a long time no without any problem, but now I would like to upgrade it a bit.

    At my home everyone like to start playing every Sonos player but no one ever pause it then they leave the room :D

    So I would like to have this option “automatically shut off if left playing but untouched for a selectable time” to save money (using 4G broadband) and bandwidth.

    I think it would be rather “simple” to have an off timer (aprox 1-2 hours) who is retrigged every time the volume or sound source is changed.

    Do you have any clue how to do this?
    jishiAuthor
    Headliner II
    January 3, 2015
    Hi Jishi,

    I have been using your excellent Sonos-lirc module running on a Raspberry Pi for a long time no without any problem, but now I would like to upgrade it a bit.

    At my home everyone like to start playing every Sonos player but no one ever pause it then they leave the room :D

    So I would like to have this option “automatically shut off if left playing but untouched for a selectable time” to save money (using 4G broadband) and bandwidth.

    I think it would be rather “simple” to have an off timer (aprox 1-2 hours) who is retrigged every time the volume or sound source is changed.

    Do you have any clue how to do this?


    I gave it a thought, but I can't come up with a reliable solution for your problem. First problem would be that one would probably not touch volume or the playlist for several hours. I know I don't, but maybe you are using it in a different way.

    Secondly, every re-subscription of the events, will trigger an event just as an update, which will act like someone had change source, volume or whatever kind of event you would use as a keep-alive check. You could of course increase the re-subscription period, but that will probably give you other issues. Next option would be to check for changes instead, but then I think the first problem would be evident.

    With a broader perspective, you could consider expanding the idea to trigger from external sources instead. The most obvious solution would be motion sensors, but that is probably too big of a project, I'm assuming. Next one would be some sort of device polling, basically associating a room, with someones mobile phone. Given the criteria that if a phone drops from your home WiFi, you would pause certain players. You could also pause everything when all phones seems to be off WiFi (aka, no one home). This could be done from the phone, or from the rPI using some sort of polling mechanism. If you had multiple access points, you could perhaps also check which one the phone is associated with (but might not work very well in a small area like a house).

    Using the phones capabilities, you could also utilize some geofencing techniques, however, in a home it would probably not be as granular as you would want it to be. This would be scriptable on android devices, using different tools, iphones would probably not be as easy.
    Lyricist III
    January 4, 2015
    Thanks a lot Jishi,
    You really spend a great amount of your time to give me a lot of new thought on this issue.

    The problem seems to be the re-subscriptions of events from other controllers (if I understand you correctly).

    I was using Android (Tasker) but have switched to IPhone/pad to keep my headache on a reasonable level.

    A different way could be to “always” set the timeout then the player goes from pause/standby to play, a bit like you already have implemented “function pauseAll(player, values)”, then you only have to toggle pause/play to keep listening.

    Or how do I set the Sonos controller original function “Sleep timer (0:15)” from your http-api? By using this function I will be able to monitor it/change it from any Sonos controller.
    jishiAuthor
    Headliner II
    January 4, 2015

    A different way could be to “always” set the timeout then the player goes from pause/standby to play, a bit like you already have implemented “function pauseAll(player, values)”, then you only have to toggle pause/play to keep listening.

    Or how do I set the Sonos controller original function “Sleep timer (0:15)” from your http-api? By using this function I will be able to monitor it/change it from any Sonos controller.


    That wasn't implemented, but seemed logical to add. It's added in 0.14 (requires discovery 0.14 as well), and you use it like this:

    /RoomName/sleep/600 (10 minutes)
    /RoomName/sleep/00:10:00

    both formats are supported.
    Lyricist III
    January 4, 2015
    Jishi you are amazing,

    The sleep function works perfectly and I also love the possibility to just set it in seconds.

    I discovered that the volume was fading out on the last 4-5 seconds and this could be used to take action to resume playing if you still is listening.

    Could you give me a hint were to find the code to hook into to detect volume/input change?
    jishiAuthor
    Headliner II
    January 4, 2015
    Jishi you are amazing,

    The sleep function works perfectly and I also love the possibility to just set it in seconds.

    I discovered that the volume was fading out on the last 4-5 seconds and this could be used to take action to resume playing if you still is listening.

    Could you give me a hint were to find the code to hook into to detect volume/input change?


    Sorry, forgot to expand on the event thing. I was probably vague, but the resubscription only applies to the node instance. When it resubscribes, it automatically triggers an event to the subscribing device. Not other controllers.

    I've never noticed the fading volume before. Since the controller actually lowers the volume, it seems to be evented, which is good. In order to act on it, you will need to listen for the "volume" event from the discovery object. It will contain a state object, that would give you the current volume, so you would need to keep a reference to the old volume on each of these emits, to have something to compare with. Something like this:

    code:

    var volumes = {};
    discovery.on('volume', function (e) {
    if (!volumes[e.uuid]) {
    // We don't have a volume entry, so trhis is the first event. Just store volume
    volumes[e.uuid] = e.state.volume;
    return;
    }

    // check if the volume is lower (potential sleep triggered)
    if (e.state.volume < volumes[e.uuid]) {
    // Volume was lowered, do something
    // to get the player, use
    // discovery.getPlayerByUUID(e.uuid)
    }
    });
    Lyricist III
    January 4, 2015
    Thanks,
    I will give the code a try!

    I just found that you can't put the sleep function in OFF mode once it started.

    I have been looking at the discovery player.js but I can't figure out how to change in the SOAP string to be able to set sleep to OFF.

    SOAP.ConfigureSleepTimer.format({time: time});
    .
    jishiAuthor
    Headliner II
    January 4, 2015
    Just send 0 as sleep time, that will disable it.

    I noticed that it would reset the volumes if you set a sleep time, I assume the same is true of you send 0.
    Lyricist III
    January 4, 2015
    Just send 0 as sleep time, that will disable it.

    I noticed that it would reset the volumes if you set a sleep time, I assume the same is true of you send 0.


    I have try with zero time without any success, it still fade out and stop playing.
    Like this “http://localhost:5005/Office/sleep/0”

    I'm using two grouped Play1, but that shouldn't be the problem?
    Lyricist III
    January 4, 2015
    To set sleep to OFF the value should be an empty string "" and not "00:00:00"
    so I have added the following code in module sleep.js function sleep(player, values).

    code:

    // zero time has to be sent as empty string
    if (timestamp == "00:00:00") {
    timestamp = "";
    }
    console.log("sleep time",timestamp)