Git Product home page Git Product logo

node-sonos-ts's Introduction

Sonos (the typescript version)

Sonos typescript this library npm Sonos api documentation Sonos2mqtt Sonos cli Join us on Discord Support me on Github

Run tests and publish github issues Coverage Status semantic-release

Typescript library to control your sonos speakers. Can be used in other typescript (or node) apps.


Key features

  • Auto generated client (supporting all features the normal app does). Sonos api documentation and generator
  • Auto discovery or one known device as starting point.
  • Support for logical devices (grouped speakers) from the start.
  • Access to all (generated) services.
  • Sonos device class with extra functionality.
  • Strongly typed service events.
  • Easier implemented metadata generation.

Documentation

To use the library just add it to your project. npm install @svrooij/sonos. And start using it. This library isn't meant to be used by itself, as you see in the examples you still need to use node (or typescript).

See Documentation

Sonos typescript this library Join us on Discord

If you need help using this library, join us on discord.

Use Sonos manager (recommended)

This library is developed with Sonos groups in mind. We created a SonosManager to discover all known groups and keep track of changes to them.

const SonosManager = require('@svrooij/sonos').SonosManager
const manager = new SonosManager()
manager.InitializeWithDiscovery(10)
  .then(console.log)
  .then(() => {
    manager.Devices.forEach(d => console.log('Device %s (%s) is joined in %s', d.Name, d.uuid, d.GroupName))
  })
  .catch(console.error)

In some network situations (or Docker usage) SSDP won't work, but you can also start the manager if you know one (static) IP of a single speaker.

const SonosManager = require('@svrooij/sonos').SonosManager
const manager = new SonosManager()
manager.InitializeFromDevice(process.env.SONOS_HOST || '192.168.96.56')
  .then(console.log)
  .then(() => {
    manager.Devices.forEach(d => console.log('Device %s (%s) is joined in %s', d.Name, d.uuid, d.GroupName))
  })
  .catch(console.error)

Single sonos speaker (no manager)

If you just want to control a single device and don't want to use the SonosManager, you can also create a instance of SonosDevice, but you'll be missing the group options.

const SonosDevice = require('@svrooij/sonos').SonosDevice

const sonos = new SonosDevice(process.env.SONOS_HOST || '192.168.96.56')
sonos.LoadDeviceData()
  .then(success => {
    console.log(sonos.Name)
  })
  .catch(console.error)

Text to speech

A lot of people want to send text to sonos to use for notifications (or a welcome message in your B&B). This library has support for text-to-speech but you'll need a text-to-speech endpoint. To keep this library as clean as possible, the text-to-speech server is build in a seperate package. See node-sonos-tts-polly for a text-to-speech server that uses Amazon Polly for speech generation.

For my sponsors I've setup a hosted version, so if you don't want to setup your own server, you know what to do.

The text-to-speech works as following:

  1. Request the TTS endpoint what the url of the supplied text is.
  2. If the server doesn't have this file, it will generate the mp3 file on the fly.
  3. The TTS endpoint returns the url of the mp3.
  4. We call the regular .PlayNotification({}) command, with the tts url.

You can also set the endpoint with the SONOS_TTS_ENDPOINT environment variable, so you don't have to supply it every time. The default language can be set with the environment variable SONOS_TTS_LANG.

The server I've build is based on Amazon Polly, but I invite eveybody to build their own if you want to support an other tts service.

const SonosDevice = require('../lib').SonosDevice
const sonos = new SonosDevice(process.env.SONOS_HOST || '192.168.96.56')
sonos.PlayTTS({ text: 'Someone at the front-door', lang: 'en-US', gender: 'male', volume: 50, endpoint: 'https://your.tts.endpoint/api/generate' })
  .then(played => {
    console.log('Played notification %o', played)
    // Timeout to allow event subscriptions to cancel.
    setTimeout(() => {
      process.exit(0)
    }, 500)
  })

Others using node-sonos-ts

Name Maintainer Description
sonos2mqtt @svrooij A bridge between sonos and mqtt, so you can control all your sonos devices right from your mqtt server
sonos-cli @svrooij An experimental command line interface for your sonos devices.

Also using this library, but not in the list? Send a PR.

Contributing

Sonos api documentation Sonos2mqtt Sonos cli Sonos typescript this library Join us on Discord

You can contribute in many ways. Asking good questions, solving bugs, sponsoring me on github. This library is build in my spare time, so don't be rude about it.

Support new music service

If you're using a music service that currently isn't supported for metadata generation, you should check out the metadata generator. It works by taking an url (which you can get by running the get-position-info sample). And generating a Track for it. Use the information out the console to get the right values. The values you'll be looking for are ProtocolInfo, TrackUri, UpnpClass, ItemID and ParentID.

Support me on Github

Contributors ✨

All Contributors

Thanks goes to these wonderful people (emoji key):


Stephan van Rooij

πŸ’» πŸ“– πŸ€” 🚧

Sven Werner

πŸ’»

H. Klages

πŸ“–

This project follows the all-contributors specification. Contributions of any kind welcome!

Developer section

This will contain usefull information if you want to fix a bug you've found in this library. You always start with cloning the repo and doing a npm install in the folder. I like consistancy so everything is in a specific order πŸ˜‰.

Running example code

This library has two VSCode launch configurations.

One for running the current open example, you can set breakpoints in the example file and in the typescript code! Be sure to change the IP to your own in .vscode/launch.json, so you don't have to edit all the example files.

And it has a launch configuration to run the current Mocha test file, be sure to have a mocha test (in test folder) open.

Service generator

Most of this library is generated by the generator. You can use the generator in your own project. Or just use the service file. I could use some help improving the code of the generator.

Big thanks to all the original contributors

Creating a library from scratch is quite hard, and I'm using a lot of stuff from node-sonos. That wouldn't exists without the contributors.

node-sonos-ts's People

Contributors

allcontributors[bot] avatar cheanrod avatar dependabot[bot] avatar gauthierm avatar hklages avatar svrooij avatar theimo1221 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

node-sonos-ts's Issues

AlbumArtUri is sometimes wrong encoded

Album Art URI does not work - prime playlist, 4. Winter-Hits, Miley Cyrus Prisoner
sonos-ts

http://192.168.178.37:1400/getaa?s=1&u=x-sonosapi-hls-static:catalog%2ftracks%2fB08LP1K9M3%2f%3fplaylistAsin%3dB08R3YYJG1%26playlistType%3dprimePlaylist%3fsid%3d201%26flags%3d0%26sn%3d19

With node-sonos JavaSript the result is the following and that works:
node-sonos

http://192.168.178.37:1400/getaa?s=1&u=x-sonosapi-hls-static%3acatalog%252ftracks%252fB08LP1K9M3%252f%253fplaylistAsin%253dB08R3YYJG1%2526playlistType%253dprimePlaylist%3fsid%3d201%26flags%3d0%26sn%3d19

TrackUri encoding when setting is incorrect

The code below needs some work, can someone point out how it should be encoded?
From src/helpers/xmlhelper.ts

  static EncodeTrackUri(trackUri: string): string {
    if (trackUri.startsWith('http')) return encodeURI(trackUri);
    if (trackUri.startsWith('x-sonos-hta')) return trackUri;

    // Part below needs some work.
    const index = trackUri.indexOf(':') + 1;
    return trackUri.substr(0, index) + this.EncodeXml(trackUri.substr(index)).replace(/:/g, '%3a');
  }

Feature: EventListener improvements

This issue describes some improvements on the EventListener endpoint

  • status endpoint (up sinces, number of received messages)
  • health endpoint, responds with http status code 200 if still running
  • maybe, websocket page to see live events (should they be raw as in xml or parsed)
  • maybe, forward all (parsed) events to an http endpoint

GroupedDeviceClass

For instances of SonosDevice created by SonosManager should have a Coordinator property. This will allow for sending commands to all speakers in a group.

Community: Link to discord

Let's discuss improvements and help each other

I've created a new community on discord so we can easily communicate about this library and other sonos api releated stuff.

Join us on Discord

UnhandledPromiseRejectionWarning - in case the sonos player is not available

(node:23976) UnhandledPromiseRejectionWarning: FetchError: request to http://192.168.178.37:1400/MediaRenderer/AVTransport/Event failed, reason: connect EHOSTUNREACH 192.168.178.37:1400
    at ClientRequest.<anonymous> (C:\Users\hekla\Development\node-red-contrib-sonos-events\node_modules\node-fetch\lib\index.js:1461:11)
    at ClientRequest.emit (events.js:315:20)
    at ClientRequest.EventEmitter.emit (domain.js:486:12)
    at Socket.socketErrorListener (_http_client.js:469:9)
    at Socket.emit (events.js:315:20)
    at Socket.EventEmitter.emit (domain.js:486:12)
    at emitErrorNT (internal/streams/destroy.js:106:8)
    at emitErrorCloseNT (internal/streams/destroy.js:74:3)
    at processTicksAndRejections (internal/process/task_queues.js:80:21)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:23976) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:23976) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

CI: Remove travis dependency

I want to migrate away from travis, because it isn't the fastest solution. The github actions finish way sooner.

Github action should be changed to:

  • Run semantic release (check if it needs a new version and then publish it)
  • Create a special dev release (from the development branch)
  • Send a trigger to sonos2mqtt action to update the dependency (new action)

InitializeWithDiscovery never terminates

Hi,

I just found this lib and it looks really promising.

I don't know if this is a bug or if it is intended but if we take this script:

import { SonosManager } from '@svrooij/sonos';

const manager = new SonosManager();
manager.InitializeWithDiscovery(10).then(console.log);

and execute it, it will never terminate. It prints true and just hangs. Is that intended?

What I want to do is to get a device that I don't know the IP of (I do however know the name/uuid).

Check event property name

playerKueche.Events.on('x', value => {
      node.send({ payload: value, topic: 'x' })
    })
 playerKueche.Events.on(SonosEvents.y, value => {
      node.send({ payload: value, topic: 'y' })
    })

does not provide any error message. Do I have to check the right "name"? Or is there something wrong in the code?

Parse ChannelMapSet from zone group state

The API makes it looks like this might return an object but because it's returned as embedded XML, it gets returned as a string.

I can decode and parse the XML manually, but it would be nice if it was done by default.

Additionally, the returned data looks to be global and not related to the current device. Should the API go on the SonosManager rather than the SonosDevice?

Describe enums

Some variables are of type string but show possible values, they should be converted to Enums.

Sample TransportState description:

<stateVariable sendEvents="no">
  <name>TransportState</name>
  <dataType>string</dataType>
  <allowedValueList>
    <allowedValue>STOPPED</allowedValue>
    <allowedValue>PLAYING</allowedValue>
    <allowedValue>PAUSED_PLAYBACK</allowedValue>
    <allowedValue>TRANSITIONING</allowedValue>
  </allowedValueList>
</stateVariable>

AVTransportService events - outputs also unchanged properties

Using this code (node.send is just to output the data):

playerKueche.AVTransportService.Events.on(ServiceEvents.Data, data => { node.send({ payload: data, topic: 'AVTransportService' }) })

Result: When pushing "stop" at Sonos app all properties and not only the changed one (here TransportState) are provided.

When using the RenderingService only the changed properties are output - as expected.

Question - unhandled promise rejection in .on callback function

Is there any other way / good practice to handle promise rejections inside event emitter function? I would like to get rid of the try..catch. But when removing them, the unhandled promise rejections are not given back to the calling asyncSubscribeToMultipleEvents.

Currently I call a wrapper asyncSubscribeToMultipleEvents to subscribe

/// async wrapper, status and error handling
    asyncSubscribeToMultipleEvents(node, subscriptions, player)
      .then((success) => {
        node.status({ fill: 'green', shape: 'ring', text: 'connected' })
        node.debug(`success >>${JSON.stringify(success)}`)  
      })
      .catch((error) => {
        node.status({ fill: 'red', shape: 'ring', text: 'disconnected' })
        node.debug(`error >>${JSON.stringify(error, Object.getOwnPropertyNames(error))}`)
      })
....
}

and then

async function asyncSubscribeToMultipleEvents (node, subscriptions, player) {

    async function sendAlarmClockMessage (raw) {
      try {
        debug('new AlarmClockService event >>', JSON.stringify(raw))
        const alarms = await player.AlarmClockService.ListAndParseAlarms()
        const payload = raw
        const topic = `household/${player.host}/alarmClock/alarmList`
        const msg = [null, null, null, null, null]
        msg[1] = { payload, alarms, topic }
        node.send(msg)  
      } catch (error) {
        node.status({ fill: 'red', shape: 'circle', text: 'error' })
        // eslint-disable-next-line max-len
        node.debug(`error during execution of event >>${JSON.stringify(error, Object.getOwnPropertyNames(error))}`)
      }
    }

    // bind events
    if (subscriptions.alarmList) {
      await player.AlarmClockService.Events.on('serviceEvent', sendAlarmClockMessage)
      debug('subscribed to AlarmClockService')
    }
...
}

The automated release is failing 🚨

🚨 The automated release from the master branch failed. 🚨

I recommend you give this issue a high priority, so other packages depending on you could benefit from your bug fixes and new features.

You can find below the list of errors reported by semantic-release. Each one of them has to be resolved in order to automatically publish your package. I’m sure you can resolve this πŸ’ͺ.

Errors are usually caused by a misconfiguration or an authentication problem. With each error reported below you will find explanation and guidance to help you to resolve it.

Once all the errors are resolved, semantic-release will release your package the next time you push a commit to the master branch. You can also manually restart the failed CI job that runs semantic-release.

If you are not sure how to resolve this, here is some links that can help you:

If those don’t help, or if this issue is reporting something you think isn’t right, you can always ask the humans behind semantic-release.


The push permission to the Git repository is required.

semantic-release cannot push the version tag to the branch master on remote Git repository.

Please refer to the authentication configuration documentation to configure the Git credentials on your CI environment.


Good luck with your project ✨

Your semantic-release bot πŸ“¦πŸš€

Events not working if using manager on multiple speakers

Hi Sven,
I have an issue with events. I use manager to find the speakers (3 of them) and then I subscribe to the events of the speakers, through the speaker object given by the manager.
What happens, is that I get the track changes and AVTransport on one speaker, but all other events will not be fired any more. If I only use the events on one speaker everything is good.
I had a close behavior on the "old" api, where events where not fired if you did subscribe multiple time to a "global" event. But with your api I don't see any more difference in global and speaker events.
Regards, Rolf

Parse stream metadata

Currentlyr:streamContent isn't parsed in the metadata. This means tune-in won't show the artist and title. This field should be parsed if the Title and Artists fields are empty.
Sample content Artist - Title

Found in svrooij/sonos2mqtt#43

Event stability

The event subscription can be a bit more stable.

  • Re-subscribe when device was removed (lost power) and comes back online.
  • Event if speaker is no longer reachable
  • Trigger event re-subscription faster (not every 50 minutes)
  • Event on subscription renewal failure (from SonosManager), to trigger application shutdown/restart.

Question: Difference between ServiceEvent, DeviceEvent

I started to develop a SONOS event node for Node-RED, based on your library. Subscribing to and receiving events works fine.

Question: What is the difference between SonosEvents, ServiceEvents?

My understanding is that ONLY the LastChange event is submitted - all others are moderated.

Therefore, the Rendering Control Service event model defines a specialized state variable (LastChange) that is used exclusively for eventing individual state changes. In this model, the LastChange state change is the only variable that is evented using the standard UPnP event mechanism. All other state variables are indirectly evented via the LastChange state variable. (Note:
A_ARG_TYPE_ state variables are not evented, either directly or indirectly.)

Improvements to SMAPI client

This library currently has a basic smapi client (Sonos music api). But it lacks support for a lot of stuff and it doesn't work with services that require authentication.

GroupRenderingControlService, removeAllListener - is not a function

Subscription works
await coordinator.GroupRenderingControlService.Events.on(ServiceEvents.Data, data => { ... }

Unsubscribing:
const x = await coordinator.GroupRenderingControlService.Events.removeAllListener(ServiceEvents.Data)

Produces an exception:

.... 
 coordinator.GroupRenderingControlService.Events.removeAllListener is not a function

Missing the "leave_group"

Hi Sven,
as supposed by you, I had a look at your typescript version. Up to now I think it's cool, as the better group handling with the manager instance is something I was looking for. But I'm missing the "leave_group" function. I think I can make the speaker leaving the group using the "group_management" service, but it would be nice to have a leave function.
Could you add this?
Thanks Rolf

Feature: Notification queue

Currently playing a notification while an other notification is already playing leads to a situation that the playback cannot be restored.

Maybe we can solve this with a NotificationQueue, my idea is to do the following (very open to suggestions):

  1. Add items to NotificationQueue
  2. If PlayingNotification (new) === true just return
  3. Capture original values to revert back to
  4. Set PlayingNotification (new) to true
  5. play all items from queue (check queue length if 0 return, take first item, play item, wait for stop, remove item from queue, call itself)
  6. Revert to original
  7. set PlayingNotification to false.

Want to pick this one up @theimo1221?

MetadataHelper should force string and do some basic string replacement (html decode)

When I play Artist Adele, Album 19 from Music library the following code (end also the full AVTransport service code):

coordinator.Events.on(SonosEvents.CurrentTrackMetadata, (data) => {
      console.log('Current track metadata %s', JSON.stringify(data, null, 2))
})

produces an "Album" property of type number - see console.log:

Current track metadata
{
  "Album":19,
  "Artist":"Adele",
  "AlbumArtUri":"http://192.168.178.37:1400/getaa?u=x-file-cifs:%2f%2fnas2019%2fMultimedia%2fMusic%2fMyMusic%2fAdele%2f19%2fAdele%20-%20Right%20as%20Rain.mp3&v=35",
  "Title":"Right as Rain",
  "UpnpClass":"object.item.audioItem.musicTrack",
  "Duration":"0:03:17",
  "ItemId":"-1",
  "ParentId":"-1",
  "TrackUri":"x-file-cifs://nas2019/Multimedia/Music/MyMusic/Adele/19/Adele - Right as Rain.mp3",
  "ProtocolInfo":"x-file-cifs:*:audio/mpeg:*"
}

In addition it would be good if you could decode Album, Title, etc. Currently I do it with:

decodeHtml: (htmlData) => {
    debug('method >>%s', 'decodeHtml')
    const decoded = String(htmlData).replace(/&lt;|&gt;|&amp;|&apos;|&quot;/g, (substring) => {
      switch (substring) {
      case '&lt;': return '<'
      case '&gt;': return '>'
      case '&amp;': return '&'
      case '&apos;': return '`'
      case '&quot;': return '"'
      }
    })
    
    return decoded
  },

You see the work around - using String to convert the number to string. Without that it throws error "replace is not a function" as 19 is number.

Wish you a Merry Christmas, Happy New Year.
Keep healthy!

Documentation: Play Notification Timeout is in seconds

Hello Team,

while using this library the timeout parameter in PlayNotification options kinda confused me.

As e.g. delay is in ms, we should either change timeout to ms too and/or document it more precisely in the interface.

Greetings

Thiemo

.AlarmClockService.ListAndParseAlarms() throws error (in case no alarms are set)

If there are no alarms the following error is thrown:

UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'Duration' of undefined
    at C:\Users\hekla\Development\node-red-contrib-sonos-events\node_modules\@svrooij\sonos\lib\services\alarm-clock.service.extension.js:32:33
    at Array.forEach (<anonymous>)
    at AlarmClockService.ListAndParseAlarms (C:\Users\hekla\Development\node-red-contrib-sonos-events\node_modules\@svrooij\sonos\lib\services\alarm-clock.service.extension.js:30:16)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async EventEmitter.sendAlarmClockMessage (C:\Users\hekla\Development\node-red-contrib-sonos-events\src\sonosevents-household.js:80:22)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:34032) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)
(node:34032) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

UnhandledPromiseRejection

(node:16948) UnhandledPromiseRejectionWarning: Error: No subscription id received
    at RenderingControlService.subscribeForEvents (C:\Users\hekla\Development\node-red-contrib-sonos-events\node_modules\@svrooij\sonos\lib\services\base-service.js:298:19)
    at runMicrotasks (<anonymous>)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async EventEmitter.<anonymous> (C:\Users\hekla\Development\node-red-contrib-sonos-events\node_modules\@svrooij\sonos\lib\services\base-service.js:280:21)
(node:16948) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 5)

Maybe because the await this.subscribeForEvents() is not in an async function?

Mute works only once

playerKueche.Events.on(SonosEvents.Mute, value => {
      node.send({ payload: value, topic: 'Mute' })
 })

playerKueche.Events.on(SonosEvents.Volume, value => {
    node.send({ payload: value, topic: 'Volume' })
})

Volume works fine, mute only once.

Event documentation

How to use the events and the advanced listener configuration.
Environment variables for listener:

  • SONOS_LISTENER_INTERFACE
  • SONOS_LISTENER_HOST
  • SONOS_LISTENER_PORT

How to unsubscribe?

Hi - me again :-) I just installed 2.2.0.

How to unsubscribe?

This code (the volume is only to demonstrate, that player is defined)

console.log('volume >>' + await player.Volume)
const x = await player.cancelAllSubscriptions()

produces:

volume >>14
(node:49824) UnhandledPromiseRejectionWarning: TypeError: player.cancelAllSubscriptions is not a function
    at cancelAll (C:\Users\hekla\Development\node-red-contrib-sonos-events\src\sonosevents-notify.js:122:28)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
(Use `node --trace-warnings ...` to show where the warning was created)
(node:49824) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1)

PlayNotification to all devices

Hi Stephan,

Is it possible to play a notification through all speakers as a group? Unless I've misunderstood, the only way I can see to achieve this is to loop through the speakers which seems to be exactly how you do it with sonos2mqtt:

return Promise.all(this.sonosManager.Devices.map(d => d.PlayNotification(payload)))

However, this results in an echo as the speakers are playing out of sync. I can correct for it to a certain degree but it's not perfect.

I tried several other approaches such as coordinator.PlayNotification() but this only plays through the targetted speaker. I tried grouping the speakers first before playing, but I suspect I've misunderstood the architecture of how this works.

Prior to this library I was using Jishi's node-http-api with clipall. As far as I can see, it seems to capture the state of each player, groups the speakers, coordinator then plays the notification and then attempts to restore the speakers to what they were. However, your library fits better into my setup and I thought I could achieve the same result.

I think it's likely I've completely underestimated what's possible with grouping and coordinator functionality or I've totally missed the point!

Would be grateful for your thoughts/help!

Thanks!

Joining a zone by name doesn't work

  sonos:device JoinGroup(kitchen) +0ms
  sonos:service:zonegrouptopology:192.168.96.3 GetZoneGroupState() +0ms
TypeError: Cannot read property 'DecodedObjectToGroups' of undefined
    at ParseZoneGroupStateResponse (node-sonos-ts/lib/helpers/zone-helper.js:7:21)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
    at async SonosDevice.JoinGroup (node-sonos-ts/lib/sonos-device.js:232:23)

Questions about Spotify and tunein

Hi, this is probably not an issue with this lib per se but I have some issues regarding Spotify and tunein, and wonder if any of you could point me in the right direction.

Play Spotify playlists.

Let's take the following code:

const device = new SonosDevice(host, port);
device.SetAVTransportURI(spotifyUri);
device.Play();

This works fine as long as spotifyUri is a single track like: spotify:track:3b9xTm2eiaCRTGqUEWuzxc but if I try a playlist: spotify:playlist:37i9dQZEVXbLoATJ81JYXz I get back Sonos error on SetAVTransportURI UPnPError 714. I get the same error if I try an artist (spotify:artist:1Xyo4u8uXC1ZmMpatF05PJ) or an album (spotify:album:6YlDIxqEjvY63ffH6AwCjd). Is this expected? Do I need to include more meta data of some sort?

Play tunein radio stations

If I run the example code from this example: https://github.com/svrooij/node-sonos-ts/blob/master/examples/music-services.js

device.MusicServicesList().then(services => {
  services.forEach(s => {
    const cap = parseInt(s.Capabilities);
    console.log(
      '%s%s\t%s\t%s\t%s',
      String(s.Id).padEnd(5, ' '),
      s.Name.padEnd(20, ' '),
      s.Policy.Auth.padEnd(9, ' '),
      s.Capabilities.toString().padStart(9, ' '),
      cap.toString(2).padStart(25, ' ')
    );
  });
}).catch(console.error);

I get for example:

277  NRK Radio           	Anonymous	    37377	         1001001000000001
235  Sveriges Radio      	Anonymous	    70145	        10001001000000001

If I then run the following code (from https://github.com/svrooij/node-sonos-ts/blob/master/examples/music-services.js):

device.MusicServicesClient('NRK Radio').then(musicClient => {
  return musicClient.Search({
    id: 'A:STATION',
    term: 'P1',
    index: 0,
    count: 10,
  });
}).then(searchResult => {
  console.log(searchResult.mediaMetadata?.[0].trackUri); // x-sonosapi-stream:live:p1?sid=277
  if (searchResult.mediaMetadata?.[0].trackUri) {
    return device.SetAVTransportURI(searchResult.mediaMetadata[0].trackUri).then(success => device.Play());
  }
}).catch(console.error);

I get the following error: Sonos error on SetAVTransportURI UPnPError 402

And if I try to search for any other station:

device.MusicServicesClient('Sveriges Radio').then(musicClient => {
  return musicClient.Search({
    id: 'A:STATION',
    term: 'P1',
    index: 0,
    count: 10,
  });
})

I get the error: Trying to access Search via searchA. How do I know what id I should pass? If I take a look at the documentation for Soson I see that I can use getMetadata. But that function does also require an id? So whatever id I try I get an error message like this back: Trying to access GetMediaMetadata via getMediaMetadataStations.

I understand that this is not an issue with this library per se but if you can guide me in the right direction I can update the documentation. Thanks.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.