Summary
The BluOS B400S is a network music streaming player controlled via the BluOS Custom Integration API (version 1.7). All commands are HTTP GET requests (except reboot which uses POST) sent to the player's IP address on port 11000. Responses are UTF-8 encoded XML. The API covers playback control, volume, play queue management, content browsing, preset management, player grouping, and input selection.
Transport
protocols:
- http
addressing:
port: 11000
base_url: "http://<player_ip>:11000"
auth:
type: none # inferred: no auth procedure in source
Traits
- levelable # volume level 0-100 and dB control commands present
- queryable # /Status and /SyncStatus queries returning state present
- powerable # /reboot command present; no power on/off toggle found in source
- routable # input selection commands present (/Play?url=, /Play?inputTypeIndex=)
Actions
# Playback Control
- id: play
label: Play
kind: action
params: []
wire:
method: GET
path: /Play
notes: Resumes playback of current audio source.
- id: play_seek
label: Play with Seek
kind: action
params:
- name: seek
type: integer
description: Position in seconds to seek to in the current track. Only valid if /Status includes <totlen>.
wire:
method: GET
path: "/Play?seek={seek}"
- id: play_url
label: Play URL
kind: action
params:
- name: url
type: string
description: URL-encoded stream URL to play directly.
wire:
method: GET
path: "/Play?url={url}"
- id: pause
label: Pause
kind: action
params: []
wire:
method: GET
path: /Pause
- id: pause_toggle
label: Pause Toggle
kind: action
params: []
wire:
method: GET
path: /Pause?toggle=1
- id: stop
label: Stop
kind: action
params: []
wire:
method: GET
path: /Stop
- id: skip
label: Skip (Next Track)
kind: action
params: []
wire:
method: GET
path: /Skip
- id: back
label: Back (Previous Track)
kind: action
params: []
wire:
method: GET
path: /Back
- id: shuffle_on
label: Shuffle On
kind: action
params: []
wire:
method: GET
path: /Shuffle?state=1
- id: shuffle_off
label: Shuffle Off
kind: action
params: []
wire:
method: GET
path: /Shuffle?state=0
- id: repeat_queue
label: Repeat Queue
kind: action
params: []
wire:
method: GET
path: /Repeat?state=0
notes: "state=0: repeat entire play queue"
- id: repeat_track
label: Repeat Track
kind: action
params: []
wire:
method: GET
path: /Repeat?state=1
notes: "state=1: repeat current track"
- id: repeat_off
label: Repeat Off
kind: action
params: []
wire:
method: GET
path: /Repeat?state=2
notes: "state=2: turn repeat off"
# Volume Control
- id: set_volume
label: Set Volume
kind: action
params:
- name: level
type: integer
description: Absolute volume level 0-100.
wire:
method: GET
path: "/Volume?level={level}"
- id: volume_up
label: Volume Up
kind: action
params:
- name: db
type: number
description: Volume increase in dB (typical value 2).
wire:
method: GET
path: "/Volume?db={db}"
- id: volume_down
label: Volume Down
kind: action
params:
- name: db
type: number
description: Volume decrease in dB (pass as negative value, e.g. -2).
wire:
method: GET
path: "/Volume?db={db}"
- id: volume_abs_db
label: Set Volume (Absolute dB)
kind: action
params:
- name: abs_db
type: number
description: Absolute volume in dB.
wire:
method: GET
path: "/Volume?abs_db={abs_db}"
- id: mute_on
label: Mute On
kind: action
params: []
wire:
method: GET
path: /Volume?mute=1
- id: mute_off
label: Mute Off
kind: action
params: []
wire:
method: GET
path: /Volume?mute=0
- id: volume_group
label: Set Volume (All Group Players)
kind: action
params:
- name: level
type: integer
description: Absolute volume level 0-100.
wire:
method: GET
path: "/Volume?level={level}&tell_slaves=1"
# Play Queue Management
- id: list_playlist
label: List Play Queue
kind: action
params: []
wire:
method: GET
path: /Playlist
- id: list_playlist_status
label: List Play Queue Status Only
kind: action
params: []
wire:
method: GET
path: /Playlist?length=1
- id: delete_track
label: Delete Track from Queue
kind: action
params:
- name: id
type: integer
description: Track position ID to delete from the play queue.
wire:
method: GET
path: "/Delete?id={id}"
- id: move_track
label: Move Track in Queue
kind: action
params:
- name: old
type: integer
description: Original position of the track.
- name: new
type: integer
description: New position for the track.
wire:
method: GET
path: "/Move?new={new}&old={old}"
- id: clear_queue
label: Clear Queue
kind: action
params: []
wire:
method: GET
path: /Clear
- id: save_queue
label: Save Queue
kind: action
params:
- name: name
type: string
description: Name for the saved playlist.
wire:
method: GET
path: "/Save?name={name}"
# Presets
- id: list_presets
label: List Presets
kind: action
params: []
wire:
method: GET
path: /Presets
- id: load_preset
label: Load Preset
kind: action
params:
- name: id
type: string
description: "Preset ID number, or +1 for next preset, or -1 for previous preset."
wire:
method: GET
path: "/Preset?id={id}"
# Content Browsing
- id: browse
label: Browse Music Content
kind: action
params:
- name: key
type: string
description: Optional browse key (URL-encoded). Absence returns top-level browse.
wire:
method: GET
path: "/Browse?key={key}"
- id: search
label: Search Music Content
kind: action
params:
- name: key
type: string
description: Search key value from a searchKey attribute in a previous browse response.
- name: q
type: string
description: The search string.
wire:
method: GET
path: "/Browse?key={key}&q={q}"
# Input Selection
- id: select_input_by_url
label: Select Input by URL
kind: action
params:
- name: url
type: string
description: URL-encoded input URL from /RadioBrowse?service=Capture response.
wire:
method: GET
path: "/Play?url={url}"
- id: select_input_by_type_index
label: Select Input by Type and Index (firmware v4.2.0+)
kind: action
params:
- name: inputTypeIndex
type: string
description: "Input type and index, e.g. spdif-1, analog-1, bluetooth-1, arc-1, earc-1, phono-1, coax-1, computer-1, aesebu-1, balanced-1, microphone-1."
wire:
method: GET
path: "/Play?inputTypeIndex={inputTypeIndex}"
notes: Requires firmware v4.2.0 or newer.
- id: select_input_by_index
label: Select Input by Index (firmware v3.8.0–v4.1.x)
kind: action
params:
- name: inputIndex
type: integer
description: 1-based index of inputs from /Settings?id=capture response, excluding Bluetooth.
wire:
method: GET
path: "/Play?inputIndex={inputIndex}"
notes: Works with firmware newer than v3.8.0 and older than v4.2.0.
# Player Grouping
- id: add_slave
label: Group a Secondary Player
kind: action
params:
- name: slave
type: string
description: IP address of the secondary player.
- name: port
type: integer
description: Port of the secondary player (default 11000).
- name: group
type: string
description: Optional group name; BluOS assigns default if not provided.
wire:
method: GET
path: "/AddSlave?slave={slave}&port={port}"
- id: remove_slave
label: Remove a Player from Group
kind: action
params:
- name: slave
type: string
description: IP address of the player to remove.
- name: port
type: integer
description: Port of the player to remove.
wire:
method: GET
path: "/RemoveSlave?slave={slave}&port={port}"
# Bluetooth
- id: set_bluetooth_mode
label: Set Bluetooth Mode
kind: action
params:
- name: bluetoothAutoplay
type: integer
description: "0=Manual, 1=Automatic, 2=Guest, 3=Disabled."
wire:
method: GET
path: "/audiomodes?bluetoothAutoplay={bluetoothAutoplay}"
notes: No response body returned.
# Doorbell
- id: doorbell_play
label: Play Doorbell Chime
kind: action
params: []
wire:
method: GET
path: /Doorbell?play=1
# Reboot
- id: reboot
label: Reboot Player
kind: action
params: []
wire:
method: POST
path: /reboot
body: "yes=1"
notes: POST request. Uses curl form: curl -d yes=1 <player_ip>/reboot (note no port in reboot example from source).
# Streaming Radio Actions
- id: radio_action
label: Execute Radio Station Action
kind: action
params:
- name: action_url
type: string
description: Full action URL as provided in the <action> element of a /Status response (e.g. /Action?service=Slacker&skip=...).
wire:
method: GET
path: "{action_url}"
notes: Used for skip, back, love, ban on streaming radio stations. The exact URL is dynamically provided per-station in the /Status response actions block.
Feedbacks
- id: playback_status
label: Playback Status
endpoint: /Status
type: xml
polling:
regular: true
long_poll: true
long_poll_params:
timeout: integer # recommended ~100 seconds
etag: string # from previous response etag attribute
key_attributes:
- state # play, pause, stop, stream, connecting, etc.
- volume # 0-100; -1 means fixed volume
- mute # 1 if muted, 0 if not
- title1 # first line of now-playing metadata (MUST be used in UI)
- title2 # second line of now-playing metadata
- title3 # third line of now-playing metadata
- album
- artist
- name
- repeat # 0=repeat queue, 1=repeat track, 2=repeat off
- shuffle # 0=off, 1=on
- quality # cd/hd/dolbyAudio/mqa/mqaAuthored or numeric bitrate
- pid # play queue id
- prid # preset id
- syncStat # sync status change indicator
- secs # seconds played (client must increment manually for play/stream state)
- totlen # total track length in seconds
- sleep # minutes until sleep timer
- canSeek # 1 if seek is possible
- canMovePlayback # true if playback can be moved to another player
- streamUrl # present when playing from streaming source (not queue)
- id: sync_status
label: Player and Group Sync Status
endpoint: /SyncStatus
type: xml
polling:
regular: true
long_poll: true
long_poll_params:
timeout: integer # recommended ~180 seconds
etag: string
key_attributes:
- name # player name
- modelName # player model name
- model # player model id
- brand # player brand
- volume # 0-100; -1 means fixed volume
- mute # 1 if muted
- group # group name
- id # player IP:port
- mac # player unique id / MAC address
- initialized # true if player is setup
- schemaVersion
- syncStat # sync status id; matches syncStat in /Status
- id: volume_state
label: Volume State
endpoint: /Volume
type: xml
key_attributes:
- volume # current volume level 0-100; -1 for fixed
- db # volume in dB
- mute # 1 if muted, 0 if not
- muteDb # unmuted volume in dB (when muted)
- muteVolume # unmuted volume 0-100 (when muted)
Variables
- id: volume_level
label: Volume Level
type: integer
range: 0-100
description: Player volume level. -1 indicates fixed volume.
get_endpoint: /Volume
set_endpoint: "/Volume?level={value}"
- id: volume_db
label: Volume Level (dB)
type: number
description: Volume level in dB. Range typically -80 to 0.
get_endpoint: /Volume
set_endpoint: "/Volume?abs_db={value}"
- id: mute_state
label: Mute State
type: boolean
description: "1 = muted, 0 = unmuted."
get_endpoint: /Volume
set_endpoint: "/Volume?mute={value}"
- id: shuffle_state
label: Shuffle State
type: boolean
description: "1 = shuffled, 0 = not shuffled."
get_endpoint: /Status
set_endpoint: "/Shuffle?state={value}"
- id: repeat_state
label: Repeat State
type: enum
values:
- 0 # repeat queue
- 1 # repeat track
- 2 # repeat off
get_endpoint: /Status
set_endpoint: "/Repeat?state={value}"
Events
# UNRESOLVED: The API supports long polling on /Status and /SyncStatus which returns when state changes.
# These are polling-based state change notifications rather than true push events.
# No unsolicited push notifications are described in the source.
- id: status_changed
label: Playback Status Changed
mechanism: long-poll
endpoint: /Status
notes: Use timeout and etag parameters. Returns only when state changes or timeout expires.
- id: sync_status_changed
label: Sync Status Changed
mechanism: long-poll
endpoint: /SyncStatus
notes: Use timeout and etag parameters. Recommended for tracking volume and grouping of players.
Macros
# UNRESOLVED: No multi-step macros are explicitly described in the source.
# The following are common integration patterns implied by the documentation:
- id: get_and_play_input
label: Discover and Select Physical Input
description: >
Step 1: GET /RadioBrowse?service=Capture to obtain current input URLs.
Step 2: GET /Play?url={URL_from_step1} to activate the input.
notes: Required for active input selection. Alternatively use /Play?inputTypeIndex= (firmware v4.2.0+).
Safety
confirmation_required_for:
- reboot # soft reboots the player; interrupts all active playback
interlocks: []
# UNRESOLVED: No electrical safety warnings or interlock procedures stated in source.
# Reboot (POST /reboot) is a disruptive action and should require confirmation in control UIs.
Notes
- All requests are HTTP GET (except /reboot which uses HTTP POST with form body
yes=1). - Port 11000 is used for all standard BluOS players. The CI580 multi-zone chassis uses ports 11000, 11010, 11020, 11030 for nodes 1-4. The actual port should be discovered via mDNS (services
musc._tcpandmusp._tcp) or via the proprietary LSDP (Lenbrook Service Discovery Protocol) using UDP broadcast on port 11430. - Long polling is supported on
/Statusand/SyncStatus. When long polling, do not make two consecutive requests for the same resource less than 1 second apart. When not long polling, restrict to at most one request every 30 seconds. - The
secsattribute in/Statusis excluded from etag calculation; clients must manually increment playback position when state isplayorstream. - When
<streamUrl>is present in/Status, the player is not using the play queue; shuffle/repeat controls and next/previous track are not applicable. - The
title1,title2,title3attributes MUST be used (notalbum/artist/name) for any 3-line now-playing UI display. Similarlytwoline_title1andtwoline_title2for 2-line displays. - Input selection for firmware v4.2.0+ uses
/Play?inputTypeIndex=type-index(e.g.spdif-2for Optical Input 2). For older firmware (v3.8.0–v4.1.x) use/Play?inputIndex=Nwhere N is the 1-based non-Bluetooth input index from/Settings?id=capture&schemaVersion=32. - Grouped players: secondary players proxy most requests to the primary player. Use
/SyncStatuslong polling to track individual secondary player volumes. - Service discovery: LSDP uses UDP broadcast on port 11430 with Announce messages ~every 60 seconds. Class ID 0x0001 = BluOS Player, 0x0003 = BluOS secondary player (multi-zone), 0x0008 = BluOS Hub.
Provenance
source_domains: []
source_urls: []
retrieved_at: 2026-06-02T21:54:06.537Z
last_checked_at: 2026-06-02T21:54:06.537Z
Verification Summary
verdict: verified
checked_at: 2026-06-02T21:54:06.537Z
matched_actions: 39
action_count: 39
confidence: medium
summary: "All 39 spec actions traced to BluOS API v1.7. Comprehensive playback, volume, input, preset, grouping, and queue management documented. (8 unresolved item(s) noted in Known Gaps.)"
Known Gaps
- "The source document is the \"BluOS Custom Integration API\" which covers many BluOS players (Bluesound, NAD Electronics, DALI Loudspeakers, etc.). The B400S model is not explicitly named in the source — spec is derived from the common BluOS CI API applicable to all standard BluOS players."
- "The API supports long polling on /Status and /SyncStatus which returns when state changes."
- "No multi-step macros are explicitly described in the source."
- "No electrical safety warnings or interlock procedures stated in source."
- "The source is the generic BluOS Custom Integration API v1.7, not a B400S-specific document. Physical input types available depend on the specific player hardware."
- "Authentication / session management: none described in source."
- "Error response format: source mentions <error> root element with <message> and <detail> child nodes for /Browse errors; full error handling across all endpoints not specified."
- "Maximum number of presets, queue length limits, or concurrent connection limits not stated in source."
- "model-specific source not located"
From the AI4AV catalog (https://ai4av.net) · ODbL-1.0