Skip to content

Commit

Permalink
Merge pull request #334 from svrooij/topology
Browse files Browse the repository at this point in the history
New way to Fetch the groups
  • Loading branch information
svrooij authored Sep 10, 2018
2 parents 90dcaac + bedd873 commit 7b7164d
Show file tree
Hide file tree
Showing 20 changed files with 1,919 additions and 2,006 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,12 @@ DeviceDiscovery((device) => {
DeviceDiscovery().once('DeviceAvailable', (device) => {
console.log('found device at ' + device.host)

// get topology
device.getTopology()
// get all groups
device.getAllGroups()
.then(console.log)
})
```


### Controlling Known Devices

```js
Expand Down Expand Up @@ -107,7 +106,7 @@ device.getVolume()
* getLEDState()
* getMusicLibrary(search, options)
* getMuted()
* getTopology()
* ~~getTopology()~~ Doesn't work if you upgraded to Sonos v9.1. Check-out getAllGroups() for some replacement.
* getVolume()
* getZoneAttrs()
* getZoneInfo()
Expand Down Expand Up @@ -136,6 +135,7 @@ device.getVolume()
* SetAlarm(id,enabled)
* joinGroup(otherDeviceName)
* leaveGroup()
* getAllGroups()
* startListening(options)
* stopListening()
* Event: 'CurrentTrack'
Expand Down Expand Up @@ -198,7 +198,7 @@ If you want to publish your own version, please do it as a [user-scoped](https:/
2. Change the `name` of the project to `@npm_username/sonos`
3. Publish it to npm `npm publish --access=public`

## Sonos v0.x
## Node Sonos v0.x (non async)

At 30 jan 2018 we released an **promisified** version of **node-sonos**. The old version can be found in the [v0.x branch](https://github.com/bencevans/node-sonos/tree/v0.x). It won't get any new features, but it **might** get security updates.

Expand Down
11 changes: 11 additions & 0 deletions docs/services/ZoneGroupTopology.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,15 @@ Sonos library to control (almost) everything from your sonos devices

Create a new instance of ZoneGroupTopology

### sonos.ZoneGroupTopology.GetZoneGroupState()

Get all the information about the ZoneGroups

**Returns**: `Object`, Object with one property, 'ZoneGroupState'

### sonos.ZoneGroupTopology.AllZoneGroups()

Get all the ZoneGroups


* * *
11 changes: 8 additions & 3 deletions docs/sonos.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,11 @@ Stop What's Playing

**Returns**: `boolean`

### sonos.Sonos.getAllGroups()

Get all the groups, replaces some functionality of 'getTopology()'


### sonos.Sonos.becomeCoordinatorOfStandaloneGroup()

Become Coordinator of Standalone Group
Expand All @@ -107,16 +112,14 @@ Leave the group (shortcut to becomeCoordinatorOfStandaloneGroup)

**Returns**: `boolean`

### sonos.Sonos.joinGroup(otherDeviceName, coordinatorOnly)
### sonos.Sonos.joinGroup(otherDeviceName)

Join an other device by name

**Parameters**:

**otherDeviceName**: `String`, The name of de device you want to join, doesn't matter if that isn't the coordinator

**coordinatorOnly**: `Boolean`, Only look of the coordinator (usefull for joined devices, eg. stereo pairs)

**Returns**: `Boolean`

### sonos.Sonos.pause()
Expand Down Expand Up @@ -306,6 +309,8 @@ Set Muted

Get Zones in contact with current Zone with Group Data

Deprecated: Doesn't work if you upgraded your system to Sonos v9.1

**Returns**: `Object`

### sonos.Sonos.getCurrentState()
Expand Down
2 changes: 1 addition & 1 deletion examples/getplaylists.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const Sonos = require('../').Sonos
const sonos = new Sonos(process.env.SONOS_HOST || '192.168.2.11')

sonos.getMusicLibrary('playlists', {start: 0, total: 25}).then(playlists => {
sonos.getMusicLibrary('playlists', { start: 0, total: 25 }).then(playlists => {
console.log('Got current playlists %j', playlists)
}).catch(err => { console.log('Error occurred %j', err) })
2 changes: 1 addition & 1 deletion examples/getsonosplaylists.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const Sonos = require('../').Sonos
const sonos = new Sonos(process.env.SONOS_HOST || '192.168.2.11')

sonos.getMusicLibrary('sonos_playlists', {start: 0, total: 25}).then(playlists => {
sonos.getMusicLibrary('sonos_playlists', { start: 0, total: 25 }).then(playlists => {
console.log('Got current playlists %j', playlists)
}).catch(err => { console.log('Error occurred %j', err) })
2 changes: 1 addition & 1 deletion examples/search.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const Sonos = require('../')

console.log('Searching for Sonos devices...')
const search = Sonos.DeviceDiscovery({timeout: 30000})
const search = Sonos.DeviceDiscovery({ timeout: 30000 })

search.on('DeviceAvailable', function (device, model) {
console.log(device, model)
Expand Down
14 changes: 14 additions & 0 deletions examples/topology.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const Sonos = require('../').Sonos
const sonos = new Sonos(process.env.SONOS_HOST || '192.168.96.57')

sonos.getAllGroups().then(groups => {
console.log('All groups %s', JSON.stringify(groups, null, 2))
}).catch(err => {
console.warn('Error loading topology %s', err)
})

sonos.zoneGroupTopologyService().GetZoneGroupAttributes().then(attributes => {
console.log('All Zone attributes %s', JSON.stringify(attributes, null, 2))
}).catch(console.warn)

// sonos.joinGroup('Slaapkamer').then(console.log).catch(console.warn)
2 changes: 1 addition & 1 deletion lib/events/adv-listener.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ class DeviceSubscription {
let sid = resp.headers.sid
debug('Got %s for %s', sid, endpoint)
this._startTimer()
this.subscriptions[sid] = {endpoint: endpoint, renew_at: this.headerToDateTime(resp.headers.timeout)}
this.subscriptions[sid] = { endpoint: endpoint, renew_at: this.headerToDateTime(resp.headers.timeout) }
return sid
})
}
Expand Down
12 changes: 6 additions & 6 deletions lib/events/eventParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ EventParser._parseAvTransportEvent = async function (body, device) {
}

device.emit('AVTransport', eventData)
return {name: 'AVTransportEvent', eventBody: eventData}
return { name: 'AVTransportEvent', eventBody: eventData }
}

EventParser._parseRenderingControlEvent = async function (body, device) {
Expand All @@ -88,11 +88,11 @@ EventParser._parseRenderingControlEvent = async function (body, device) {
}
}
device.emit('RenderingControl', eventData)
return {name: 'RenderingControlEvent', eventBody: eventData}
return { name: 'RenderingControlEvent', eventBody: eventData }
}

EventParser._genericEvent = function (endpoint, body, device) {
const event = {name: 'UnknownEvent', endpoint: endpoint, eventBody: body}
const event = { name: 'UnknownEvent', endpoint: endpoint, eventBody: body }
if (device) {
device.emit(event.name, event)
}
Expand All @@ -102,7 +102,7 @@ EventParser._genericEvent = function (endpoint, body, device) {

EventParser._parseAlarmEvent = function (body, device) {
debug('Alarm event %j', body)
let event = {name: 'AlarmClock', eventBody: body}
let event = { name: 'AlarmClock', eventBody: body }
return event
}

Expand All @@ -118,11 +118,11 @@ EventParser._parseZoneGroupTopologyEvent = async function (body, device) {
eventData[firstKey] = element[firstKey]
}
}
return {name: 'ZoneGroupTopology', eventBody: eventData}
return { name: 'ZoneGroupTopology', eventBody: eventData }
}

EventParser._parseGroupRenderingControlEvent = function (body, device) {
let event = {name: 'GroupRenderingControl', eventBody: body, device: {host: device.host, port: device.port}}
let event = { name: 'GroupRenderingControl', eventBody: body, device: { host: device.host, port: device.port } }
return event
}

Expand Down
2 changes: 1 addition & 1 deletion lib/events/listener.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var Listener = function (device, options) {
this.device = device
this.parser = new xml2js.Parser()
this.services = {}
this.options = options || {'interface': 'public'} // If you want to use a different interface for listening, specify the name in options.interface
this.options = options || { 'interface': 'public' } // If you want to use a different interface for listening, specify the name in options.interface
}

util.inherits(Listener, events.EventEmitter)
Expand Down
8 changes: 4 additions & 4 deletions lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Helpers.GenerateMetadata = function (uri, title = '', region = '3079') {
var parts = uri.split(':')
if (!((parts.length === 2 && (parts[0] === 'radio' || parts[0] === 'x-sonosapi-stream' || parts[0] === 'x-rincon-cpcontainer')) || (parts.length >= 3 && parts[0] === 'spotify'))) {
debug('Returning string because it isn\'t recognized')
return {uri: uri, metadata: ''}
return { uri: uri, metadata: '' }
}
var meta = '<DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:r="urn:schemas-rinconnetworks-com:metadata-1-0/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"><item id="##SPOTIFYURI##" ##PARENTID##restricted="true"><dc:title>##RESOURCETITLE##</dc:title><upnp:class>##SPOTIFYTYPE##</upnp:class><desc id="cdudn" nameSpace="urn:schemas-rinconnetworks-com:metadata-1-0/">##REGION##</desc></item></DIDL-Lite>'

Expand Down Expand Up @@ -130,7 +130,7 @@ Helpers.GenerateMetadata = function (uri, title = '', region = '3079') {
.replace('##PARENTID##', '')
}
} else {
return {uri: uri, metadata: ''}
return { uri: uri, metadata: '' }
}
}

Expand Down Expand Up @@ -179,10 +179,10 @@ Helpers.TimeToSeconds = function (time) {
}

Helpers._ParseXml = function (input, callback) {
return parseString(input, {mergeAttrs: true, explicitArray: false}, callback)
return parseString(input, { mergeAttrs: true, explicitArray: false }, callback)
}

const playbackStates = {'STOPPED': 'stopped', 'PLAYING': 'playing', 'PAUSED_PLAYBACK': 'paused', 'TRANSITIONING': 'transitioning', 'NO_MEDIA_PRESENT': 'no_media'}
const playbackStates = { 'STOPPED': 'stopped', 'PLAYING': 'playing', 'PAUSED_PLAYBACK': 'paused', 'TRANSITIONING': 'transitioning', 'NO_MEDIA_PRESENT': 'no_media' }
/**
* Convert the playbackstate to a bit more readable
* @param {String} state Sonos playback state
Expand Down
38 changes: 19 additions & 19 deletions lib/services/AVTransport.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,22 +62,22 @@ AVTransport.prototype.AddMultipleURIsToQueue = async function (options) { return
AVTransport.prototype.ReorderTracksInQueue = async function (options) { return this._request('ReorderTracksInQueue', options) }
AVTransport.prototype.RemoveTrackFromQueue = async function (options) { return this._request('RemoveTrackFromQueue', options) }
AVTransport.prototype.RemoveTrackRangeFromQueue = async function (options) { return this._request('RemoveTrackRangeFromQueue', options) }
AVTransport.prototype.RemoveAllTracksFromQueue = async function () { return this._request('RemoveAllTracksFromQueue', {InstanceID: 0}) }
AVTransport.prototype.RemoveAllTracksFromQueue = async function () { return this._request('RemoveAllTracksFromQueue', { InstanceID: 0 }) }
AVTransport.prototype.SaveQueue = async function (options) { return this._request('SaveQueue', options) }
AVTransport.prototype.BackupQueue = async function (options) { return this._request('BackupQueue', options) }
AVTransport.prototype.GetMediaInfo = async function () { return this._request('GetMediaInfo', {InstanceID: 0}) }
AVTransport.prototype.GetTransportInfo = async function () { return this._request('GetTransportInfo', {InstanceID: 0}) }
AVTransport.prototype.GetPositionInfo = async function () { return this._request('GetPositionInfo', {InstanceID: 0}) }
AVTransport.prototype.GetDeviceCapabilities = async function () { return this._request('GetDeviceCapabilities', {InstanceID: 0}) }
AVTransport.prototype.GetTransportSettings = async function () { return this._request('GetTransportSettings', {InstanceID: 0}) }
AVTransport.prototype.GetCrossfadeMode = async function () { return this._request('GetCrossfadeMode', {InstanceID: 0}) }
AVTransport.prototype.Stop = async function () { return this._request('Stop', {InstanceID: 0}) }
AVTransport.prototype.Play = async function () { return this._request('Play', {InstanceID: 0, Speed: 1}) }
AVTransport.prototype.Pause = async function () { return this._request('Pause', {InstanceID: 0}) }
AVTransport.prototype.GetMediaInfo = async function () { return this._request('GetMediaInfo', { InstanceID: 0 }) }
AVTransport.prototype.GetTransportInfo = async function () { return this._request('GetTransportInfo', { InstanceID: 0 }) }
AVTransport.prototype.GetPositionInfo = async function () { return this._request('GetPositionInfo', { InstanceID: 0 }) }
AVTransport.prototype.GetDeviceCapabilities = async function () { return this._request('GetDeviceCapabilities', { InstanceID: 0 }) }
AVTransport.prototype.GetTransportSettings = async function () { return this._request('GetTransportSettings', { InstanceID: 0 }) }
AVTransport.prototype.GetCrossfadeMode = async function () { return this._request('GetCrossfadeMode', { InstanceID: 0 }) }
AVTransport.prototype.Stop = async function () { return this._request('Stop', { InstanceID: 0 }) }
AVTransport.prototype.Play = async function () { return this._request('Play', { InstanceID: 0, Speed: 1 }) }
AVTransport.prototype.Pause = async function () { return this._request('Pause', { InstanceID: 0 }) }
AVTransport.prototype.Seek = async function (options) { return this._request('Seek', options) }
AVTransport.prototype.Next = async function () { return this._request('Next', {InstanceID: 0}) }
AVTransport.prototype.Next = async function () { return this._request('Next', { InstanceID: 0 }) }
AVTransport.prototype.NextProgrammedRadioTracks = async function () { return this._request('NextProgrammedRadioTracks') }
AVTransport.prototype.Previous = async function () { return this._request('Previous', {InstanceID: 0}) }
AVTransport.prototype.Previous = async function () { return this._request('Previous', { InstanceID: 0 }) }
AVTransport.prototype.NextSection = async function (options) { return this._request('NextSection', options) }
AVTransport.prototype.PreviousSection = async function (options) { return this._request('PreviousSection', options) }

Expand All @@ -86,11 +86,11 @@ AVTransport.prototype.PreviousSection = async function (options) { return this._
* @param {string} playmode One of the following `NORMAL` `REPEAT_ALL` `SHUFFLE` `SHUFFLE_NOREPEAT`
* @returns {Object} Parsed response data.
*/
AVTransport.prototype.SetPlayMode = async function (playmode) { return this._request('SetPlayMode', {InstanceID: 0, NewPlayMode: playmode}) }
AVTransport.prototype.SetPlayMode = async function (playmode) { return this._request('SetPlayMode', { InstanceID: 0, NewPlayMode: playmode }) }
AVTransport.prototype.SetCrossfadeMode = async function (options) { return this._request('SetCrossfadeMode', options) }
AVTransport.prototype.NotifyDeletedURI = async function (options) { return this._request('NotifyDeletedURI', options) }
AVTransport.prototype.GetCurrentTransportActions = async function () { return this._request('GetCurrentTransportActions', {InstanceID: 0}) }
AVTransport.prototype.BecomeCoordinatorOfStandaloneGroup = async function () { return this._request('BecomeCoordinatorOfStandaloneGroup', {InstanceID: 0}) }
AVTransport.prototype.GetCurrentTransportActions = async function () { return this._request('GetCurrentTransportActions', { InstanceID: 0 }) }
AVTransport.prototype.BecomeCoordinatorOfStandaloneGroup = async function () { return this._request('BecomeCoordinatorOfStandaloneGroup', { InstanceID: 0 }) }
AVTransport.prototype.DelegateGroupCoordinationTo = async function (options) { return this._request('DelegateGroupCoordinationTo', options) }
AVTransport.prototype.BecomeGroupCoordinator = async function (options) { return this._request('BecomeGroupCoordinator', options) }
AVTransport.prototype.BecomeGroupCoordinatorAndSource = async function (options) { return this._request('BecomeGroupCoordinatorAndSource', options) }
Expand All @@ -100,18 +100,18 @@ AVTransport.prototype.BecomeGroupCoordinatorAndSource = async function (options)
* @param {string} duration the duration as 'ISO8601Time', needs sample!
* @returns {Object} Parsed response data.
*/
AVTransport.prototype.ConfigureSleepTimer = async function (duration) { return this._request('ConfigureSleepTimer', {InstanceID: 0, NewSleepTimerDuration: duration}) }
AVTransport.prototype.GetRemainingSleepTimerDuration = async function () { return this._request('GetRemainingSleepTimerDuration', {InstanceID: 0}) }
AVTransport.prototype.ConfigureSleepTimer = async function (duration) { return this._request('ConfigureSleepTimer', { InstanceID: 0, NewSleepTimerDuration: duration }) }
AVTransport.prototype.GetRemainingSleepTimerDuration = async function () { return this._request('GetRemainingSleepTimerDuration', { InstanceID: 0 }) }
AVTransport.prototype.RunAlarm = async function (options) { return this._request('RunAlarm', options) }
AVTransport.prototype.StartAutoplay = async function (options) { return this._request('StartAutoplay', options) }
AVTransport.prototype.GetRunningAlarmProperties = async function (options) { return this._request('GetRunningAlarmProperties', {InstanceID: 0}) }
AVTransport.prototype.GetRunningAlarmProperties = async function (options) { return this._request('GetRunningAlarmProperties', { InstanceID: 0 }) }

/**
* Snooze the current running alarm for a number of minutes.
* @param {string} duration The duration, as 'ISO8601Time', needs sample!
* @returns {Object} Parsed response data.
*/
AVTransport.prototype.SnoozeAlarm = async function (duration) { return this._request('SnoozeAlarm', {InstanceID: 0, Duration: duration}) }
AVTransport.prototype.SnoozeAlarm = async function (duration) { return this._request('SnoozeAlarm', { InstanceID: 0, Duration: duration }) }

/**
* Get information about the current track, parsed version of `GetPositionInfo()`
Expand Down
Loading

0 comments on commit 7b7164d

Please sign in to comment.