Unofficial PowerShell wrapper of the BluOS Web/REST API, served by Bluesound multi-room music devices. The main objective for now is to have a test bench for exploring the features of the API, not an extremely robust and efficient interface.
Bluesound is an award-winning wireless hi-res sound system (https://www.bluesound.com/).
BluOS is an advanced operating system and music management software (https://nadelectronics.com/bluos/).
Note that several of the services integrated into BluOS, such as Tidal, have their own APIs that can be used directly instead of (or in addition to) via the integrated API in BluOS. For Tidal, see tidalshell - my PowerShell wrapper for the Tidal API.
Most of the information here was found by reverse engineering the BluOS Controller desktop application. Since then an official API documentation has been published on bluesound.com/downloads. Until I can make time for a complete review there may be discrepancies. More about sources at the end.
The BluOS devices serve a REST API on port number 11000. Most operations can be performed with HTTP Get requests, some very few require HTTP Post. Responses are XML.
On port 80 there is a basic web user interface, and some operations must be done with HTTP requests to this service instead of the REST service.
When describing the details below, all operations are HTTP Get requests against the REST API unless specifically stated otherwise.
Without parameters it will resume playback from the current position of the play queue or the latest stream.
Optional parameter id
can be set to a positive integer identifying the item number in the play queue to start playback from.
Optional parameter seek
can be set to a integer representing number of seconds into the current track to start playback from.
Optional parameter url
can be set directly to a stream url to play. This can
be any streamable media url, such as an mp3 file, or it can be an "internal"
url identifier used in BluOS, e.g. Capture:bluez:bluetooth
or Tidal​:radio:track/43781115
(the latter from the trackstationid attribute
of /Songs response from Tidal service).
The response indicates the resulting state, which is also reported by /Status. On success the state should be play
.
Additional notes regarding url playback
Playing a custom stream url can also be done via the TuneIn service, by adding it as a "Custom Station". Then the stream url will be saved and can be added as a favorite, assigned to a preset etc. This is actually the only officially supported method for playing custom streams: "TuneIn Custom Stations replaces the option in BluOS 1.20.x and earlier versions to enter a custom URL in the Configure Player Menu." (https://support1.bluesound.com/hc/en-us/articles/217463777-Save-an-Internet-Stream-as-a-Custom-Station-in-TuneIn)
In addition to the REST API method for playing url, the Web interface also has
support for it. On http://<device_address>/playurl there is an interactive input form
for entering an url, and it can be triggered programmatically by sending a HTTP Post
request with parameter url
containing the stream URL.
Without parameters it will suspend playback at the current position, if it is currently playing.
The response indicates the resulting state, which is also reported by /Status. On success the state should be pause
.
Optional parameter toggle
can be set to integer value 1 to toggle between play and pause states. The response indicates the resulting state, which is also reported by /Status. On success the state could be either play
or pause
.
Stop playback. The official app seem to only supports play and pause as interactive operations, not stop. When device is activated from "vacation mode" it is in the stopped state.
The response indicates the resulting state, which is also reported by /Status. On success the state should be stop
.
Moves playback to the next item in the current play queue, wrapping around to
first when currently at the last item. The response contains
the id
value of the moved to item.
Moves playback to the previous item in the current play queue, wrapping around
to last when currently at the first item. The response contains
the id
value of the moved to item.
Without parameters the response returns the id
of the current play queue and the current
state of the repeat option. Value is an integer with the following meaning:
0
means repeat entire playqueue1
means repeat current track2
means no repeat
Optional parameter state
can be specified to modify, with an integer value
indicating the repeat mode to set. The response indicates
the resulting state.
The current state can be retrieved from the /Status request as well.
Without parameters this does not (just) return the current state, but it turns shuffle off! To get the current state without modifying one must fetch it from the /Status request.
The response contains the id
of the current play queue,
and the current state of the repeat option (although the current state may not be
included when shuffle is off). Value is an integer with the following meaning:
0
means off1
means on
Optional parameter state
can be specified to modify, with an integer value
indicating the repeat mode to set. The response
indicates the resulting state.
Without parameters the response informs about the current setting, in percent and dB unit.
Optional parameter level
can be specified to modify, with an integer value
between 0 and 100 specifying the volume in percent to set. The
response when modifying does only contain the changed
setting in percent, not in dB unit as when just requesting the current value.
The current volume in percent (volume
) and dB (outlevel
) can be retrieved
from the /SyncStatus request as well, and in percent also from the /Status request.
Without parameters the response describes the current play queue.
It is identified by a name
and id
, and a list of entries (song
) with
increasing id
starting from 0. The entry ids are referenced in the response from
the /Skip and /Prev requests. The playlist id is also referenced from
other requests working on the play queue, and it seems to be an integer
that is incremented whenever the playlist is changed.
Optional parameters start
and/or end
can be specified to return
an excerpt of the play queue. The values refer to id
of playlist
entries, zero indexed, and the specified end is inclusive (start=0&end=0
will give a single, the first, item).
Empties the current play queue, and returns the same response
as a request to /Playlist would do: An empty playlist
element but
an incremented id
.
Saves the current play queue as a new playlist. Required parameter name
specifies the playlist name.
Response on success contains an element saved
, with a sub-element entries
containing the number of items in the saved playlist.
Adding items to the current playqueue, and optionally start playback.
Optional argument service
indicates where the item is located.
Optional argument playlist
, file
, albumid
, artistid
, etc identifies the item.
Optional argument where
can be specified to indicate where in the queue
to add the new items. Possible values are next
, last
, nextAlbum
, etc.
Optional argument playnow
can be set to value 1 to trigger playback.
TODO: More details needed!
BluOS supports grouping players in different modes:
- Multi-player group
- Stereo pair
- Home theater group
In the official app there are two main roads to creating a group:
- Quick create multi-player group from the player drawer, either
by clicking
+
symbol on players to add to current player's group, or by clicking the "Group all" button. These will always be multi- player groups, and they will get an auto-generated name as a combination of the individual names of the players. - Fixed groups menu, where you can select any of the supported group modes, get help configuring them (e.g. pick which one is left and which is right in a stereo pair, by playing a sound on each of them), and also give the group a custom name.
A device can be added to a group by specifying the device address
in parameter slave
. It seems to support alternative parameter
slaves
where multiple devices can be specified at once, probably
comma-separated, but have not had a chance to test this.
Optional parameter port
(or ports
) can be specified if any
of the devices use a non-standard port number (other than the
default 11000).
Optional parameter group
can be specified to give the group a name,
by default it will be generated from the names of the devices.
This will set up a multi-player group. To set up a stereo pair
one must also specify parameters channelMode
and slaveChannelMode
,
one of them with value left
and the other one with value right
.
(Multi-player group have implicit value default
for both
channelMode
and slaveChannelMode
).
TODO: How to set up Home theater group?
The response contains the address and port numbers of slaves added.
Removes a device from a group, and the entire when there are only
one device in it. Required parameter slave
or slaves
, and
optional parameter port
or ports
.
The response contains the SyncStatus.
This seem to return a more or less complete description of the navigation paths of all supported services in the user interface. A lot of API details can be found by inspecting this!
TODO: More details...
This can be used to browse the content of configured services (Tidal, Qobuz, TuneIn, etc). The first call gets a list of menu items with 'browse keys' which can be used in subsequent calls. Provided search keys can be used to search the service that is being browsed.
Samples:
/Browse?key=Qobuz:Search&q=miles
Returns list of all current presets. Players such as Bluesound Flex have physical buttons for 5 presets, but the API supports configuring up to 40 different presets that can be triggered with the /Preset request (see below).
Sample response.
Activates a preset (starts playback), identified by parameter id
.
Sample response for playlist preset and radio preset.
Without parameters it lists existing presets, identical to /Presets.
To modify a preset the preset number must be specified in parameter id
.
If no other parameters are specified it will remove any existing presets with that identifier.
To set a new preset the service must be specified in parameter service
(e.g. Capture
, or Tidal
),
and the BluOS specific reference must be specified in parameter encoded_url
(for example for the
preset to switch active source to Bluetooth, the url is "Capture:bluez:bluetooth"). A preset name
must be specified in parameter name
. Then there is an option to include a volume level, so that
activating the preset also changes the volume, then the parameter volume
must specify the volume in percent.
There is also a parameter image
.
In all variants the response is the list of current presets, as also returned by /Presets.
Returns available playlists. Note /Playlist (without ending s) is similar, but not directly related as it returns the current play queue.
Without parameters it returns local device playlists, as if parameter service
is set to LocalMusic
. Playlists from other services can be listed by setting
parameter service
, e.g. to Tidal
.
Sample response for the default service (LocalMusic
),
and response for service=Tidal.
At least for Tidal, the default is to return your personal playlists. Other compiled playlists can be retrieved by adding various parameters:
category
:new
,recommended
,local
,FAVOURITES
genre
:Local
,Pop
,Rock
, etc (genreid of items returned by /Genres).mood
:relax
,party
,workout
, etc (genreid of items returned by /Genres withcategory=moods
)
Playlists can be created by /Save, /AddToPlaylist etc..
TODO...
Create (or modify) playlists.
Parameter name
must be set with the name to save it as.
Parameter service
identifies where to save the playlist, e.g. LocalMusic
to save it on the device.
Parameters sourceService
and songid
identifies the item to add to the playlist.
TODO...
Sample default response, service=Capture response , service=TuneIn response.
TODO...
Sample default response, service=TuneIn.
TODO...
TODO...
TODO...
Lists the generes supported by a given service, default is the local player
but parameter service
can be specified to see genres from other services
(such as Tidal).
Other service-specific parameters may be supported, e.g. Tidal supports
category=moods
to get the categories of special "mood" playlists.
Sample default response, service=Tidal response.
For Tidal navigation the parameter service
must be set to Tidal
.
In addition one need to specify one or more parameters for navigating
into the structure, similar to /Playlists:
category
:new
,rising
,recommended
,top
,local
,FAVOURITES
genre
:Local
,Pop
,Rock
, etc (genreid of items returned by /Genres).
For /Songs one can specify attribute playlistid
to list all songs
in a specified playlist, or albumid
to list all songs in an album.
To perform a generic search, specify parameter expr
with the search string as value. It will search local music by default, but to search other services add parameter service
(e.g. service=Tidal). The response contains search results, groupd on artist, album and song.
Sample default response, service=Tidal response.
Another way of searching is through /Browse (see above).
To search for radio stations, using a similar syntax as /Search: Parameter expr
with the search string, and service
to identify the service - here TuneIn is the default service.
Sample response.
Redirects to the image file representing an item, such as an artist, album, song,
radio station. Parameter identifies the item, either songid
, albumid
, artistid
or playlistid
.
Sample response.
Gets a html page with a description of an artist, album or song.
Sample: /Info?service=Qobuz&service=Qobuz&artistid=574073
HTTP Post request with parameter set
with the new name as the value will set the
name of the player - the "room name".
Gives the current status of the player. This is called frequently by the offical applications to keep it up to date with any changes from other controllers.
Two optional parameters, timeout
, which can be set to an integer value
which defines number of seconds, and etag
, which is an
HTTP entity tag, are
used for 'long polling', keeping the request open until the responsive is different from the previous response (using the etag for comparison) or until the timeout has been reached. /SyncStatus should be polled if only the name, volume and grouping status of a player is of interest. /Status should be polled if current playback status is needed. The official desktop client application sends these requests regularly (every few seconds).
(The official destkop client does not send "If-None-Match" headers, which is normally used in Etag concurrency control Tidal does, it is implemented in tidalshell).
Sample response, response when stopped, response when paused, response when playing.
Used in combination with /Status to keep multiple controllers synchronized.
Sample response.
TODO: Have not yet dug into exactly how the synchronization mechanism works..
Similar to /Services, this gives seem to return a more or less complete description of the navigation paths of settings in the user interface. A lot of API details can be found by inspecting this!
TODO: More details...
Sets the sleep timer, each request will cycle through the supported settings: 15, 30, 45, 60, 90 minutes, and off. Response is the new setting in number of minutes, or empty if it is off. Current value can be found from /Status.
Without parameters the response lists all existing alarm definitions.
Parameter tz
can be set specify time zone, value is string containing the "Olson"
time zone name.
Alarms can be created by setting various parameters:
hour
: Hour of day as an integer.minute
: Minutes of the hour as an integer.days
: Repetition, specified as string with 7 binary values representing weekdays (SMTWTFS), "00000000" means no repetition, "1010000" means sundays and tuesdays.duration
: Timeout in minutes before the alarm turns off automatically, 0 means never. Official application supports between 15 minutes and 2 hours.source
: The alarm sound.volume
: The alarm sound volume, in percent.fadeIn
: If the alarm sound should fade in, value is 0 or 1.image
: TODO...url
: TODO...enable
: Value is 1. Official application does not support enabling/disabling alarms, so not sure what this is for, if we can set it to value 0? TODO...tz
: The timezone name.
Reponse from creating alarms is the same as /Alarms; listing all current alarms.
Alarms can be modified by including parameter id
identifying the alarm entry, and then any of the above parameters that should be modified. Response is same as /Alarms; listing all current alarms.
Alarms can be deleted by including parameter id
identifying the alarm entry and then parameter delete
with value 1. Response is same as /Alarms; listing all current alarms.
Without parameters the response indicates the current value of all "audio mode" related settings. EDIT: Tested 21.04.2021 and did no longer get current values, but changes chan still be performed as described next.
NOTE: The audio options vary depending on the model of the BluOS Player, see the following article.
Changes must be performed using an HTTP Post request (not a Get request like most other operations on the REST API), and with parameters specifying the new value of any settings to change:
bluetoothAutoplay
, integer value:0
means manual1
means automatic2
means guest3
means off
channelMode
default
(means mono output on a mono speaker like Flex, otherwise probably stereo output?)left
right
mono
(guessing this is a value for setting mono output on a stereo speaker?)
volumeLimits
- Value is the decibel integer range separated by comma, e.g.
-90,0
.
- Value is the decibel integer range separated by comma, e.g.
volume
volMin
volMax
volMinDefault
volMaxDefault
volMinLimit
volMaxLimit
volRamp
volRampDefault
mqaDisable
crossover
canFixVolume
replayGainMode
none
track
album
smart
captureLatency
captureAutoplay
A post request with parameter reset
set to value 1
will reset all audio settings to defaults.
Adjusting the LED brightness setting is possible via the Web API, not the REST API.
It is achieved by sending an HTTP Post request with parameter brightness
with
string value which is one of:
default
dim
off
Lists current IR remote configuration?
TODO...
IR remote related?
TODO...
Rebooting the player device is possible via the Web API, not the REST API. Using the basic
web interface, http://<device_address>/reboot will give you an interactive user interface
with buttons Yes and No (parameter noheader=1
can be added for an even more minimalistic
and stand-alone web interface, without the navigation menu on top). An HTTP Post request
with parameter yes
will trigger the actual reboot.
The Web interface supplies an internal diagnostics log in text format, which can
be retrieved with an HTTP Get request with parameter print
set to integer 1 (http://<device_address>/diag?print=1).
The starting point was a thread on the official Bluesound forum. I also looked at the Python Bluesound API by @venjum, which have implemented many of the basic features mentioned in the thread.
Most of the information is from my own investigations, mainly by reverse engineering what the BluOS Controller desktop application is doing. My main tool for reverse engineering APIs is Telerik Fiddler. In this case the official desktop client application is based on Electron (Chromium), and then it is possible to open up the built-in developer tools using "secret" shortcut Ctrl+Shift+E (or Ctrl+E+V), which is also very useful.
You could also use Wireshark.
Since this was written an official API documentation has been published on bluesound.com/downloads, as a downloadable PDF. The official documentation is incomplete.
There are also different plugins for integrating into specific home automation systems.