Summary

BluOS is an advanced operating system and music management software used in products from Bluesound, NAD Electronics, DALI Loudspeakers, and others. This spec covers the HTTP-based Custom Integration API (version 1.7), focusing on volume control, mute, playback control, play queue management, presets, content browsing, player grouping, and supporting commands. All requests are HTTP GET (except reboot, which is POST), sent to the player IP on port 11000 (default), with responses returned as UTF-8 encoded XML.

Transport

protocols:
  - http
addressing:
  host: "<player_ip>"  # discovered via mDNS (musc._tcp / musp._tcp) or LSDP (UDP broadcast port 11430)
  port: 11000  # default for all BluOS players except CI580 multi-node chassis (nodes use 11000, 11010, 11020, 11030)
  base_url: "http://<player_ip>:11000"
auth:
  type: none  # inferred: no auth procedure in source

Traits

- levelable    # inferred from volume set/up/down/mute commands
- queryable    # inferred from /Status, /SyncStatus, /Volume query commands returning state
- routable     # inferred from input selection commands and player grouping commands

Actions

# --- Volume Control ---

- id: set_volume_level
  label: Set Volume Level
  kind: action
  endpoint: "GET /Volume"
  params:
    - name: level
      type: integer
      range: "0..100"
      description: Absolute volume level (0–100).
    - name: tell_slaves
      type: integer
      range: "0|1"
      description: "If 1, applies to all grouped players. If 0, only the selected player."
      required: false

- id: set_volume_db
  label: Set Volume (Absolute dB)
  kind: action
  endpoint: "GET /Volume"
  params:
    - name: abs_db
      type: number
      description: Absolute volume in dB (constrained to configured available range, typically -80..0).
    - name: tell_slaves
      type: integer
      range: "0|1"
      required: false

- id: adjust_volume_db
  label: Adjust Volume (Relative dB)
  kind: action
  endpoint: "GET /Volume"
  params:
    - name: db
      type: number
      description: Relative volume change in dB (positive = up, negative = down; typical +2 or -2).
    - name: tell_slaves
      type: integer
      range: "0|1"
      required: false

- id: mute_on
  label: Mute
  kind: action
  endpoint: "GET /Volume?mute=1"
  params:
    - name: mute
      type: integer
      value: 1
      description: Set to 1 to mute player.
    - name: tell_slaves
      type: integer
      range: "0|1"
      required: false

- id: mute_off
  label: Unmute
  kind: action
  endpoint: "GET /Volume?mute=0"
  params:
    - name: mute
      type: integer
      value: 0
      description: Set to 0 to unmute player.
    - name: tell_slaves
      type: integer
      range: "0|1"
      required: false

# --- Playback Control ---

- id: play
  label: Play
  kind: action
  endpoint: "GET /Play"
  params:
    - name: seek
      type: integer
      description: Jump to position in seconds in the current track. Only valid if /Status response includes <totlen>.
      required: false
    - name: id
      type: integer
      description: Track id in the play queue. Used with seek.
      required: false
    - name: url
      type: string
      description: URL-encoded stream URL for direct stream playback.
      required: false

- id: pause
  label: Pause
  kind: action
  endpoint: "GET /Pause"
  params:
    - name: toggle
      type: integer
      value: 1
      description: If set to 1, toggles the current pause state.
      required: false

- id: stop
  label: Stop
  kind: action
  endpoint: "GET /Stop"
  params: []

- id: skip
  label: Skip to Next Track
  kind: action
  endpoint: "GET /Skip"
  params: []
  notes: "Only valid when playing from play queue (no <streamUrl> in /Status response)."

- id: back
  label: Back / Previous Track
  kind: action
  endpoint: "GET /Back"
  params: []
  notes: "If track has been playing more than 4 seconds, returns to start of current track; otherwise goes to previous track. Only valid from play queue."

- id: shuffle
  label: Set Shuffle
  kind: action
  endpoint: "GET /Shuffle"
  params:
    - name: state
      type: integer
      range: "0|1"
      description: "0 to disable shuffle, 1 to enable shuffle."

- id: repeat
  label: Set Repeat
  kind: action
  endpoint: "GET /Repeat"
  params:
    - name: state
      type: integer
      range: "0|1|2"
      description: "0 = repeat queue, 1 = repeat current track, 2 = repeat off."

- id: stream_action
  label: Streaming Radio Action (skip/back/love/ban)
  kind: action
  endpoint: "GET /Action"
  params:
    - name: service
      type: string
      description: Service name (e.g., Slacker, RadioParadise).
    - name: action
      type: string
      description: Action parameter as provided by <action> element in /Status response.
  notes: "Specific URL is provided by <action> elements in /Status response. Only available for supported streaming radio stations."

# --- Play Queue Management ---

- id: list_queue
  label: List Play Queue
  kind: action
  endpoint: "GET /Playlist"
  params:
    - name: length
      type: integer
      value: 1
      description: "If 1, return only top-level queue attributes without track details."
      required: false
    - name: start
      type: integer
      description: First entry to include (0-based). Used for pagination.
      required: false
    - name: end
      type: integer
      description: Last entry to include. Used for pagination.
      required: false

- id: delete_track
  label: Delete Track from Queue
  kind: action
  endpoint: "GET /Delete"
  params:
    - name: id
      type: integer
      description: Track position id to remove from play queue.

- id: move_track
  label: Move Track in Queue
  kind: action
  endpoint: "GET /Move"
  params:
    - name: new
      type: integer
      description: New position for the track.
    - name: old
      type: integer
      description: Current position of the track.

- id: clear_queue
  label: Clear Play Queue
  kind: action
  endpoint: "GET /Clear"
  params: []

- id: save_queue
  label: Save Play Queue as Playlist
  kind: action
  endpoint: "GET /Save"
  params:
    - name: name
      type: string
      description: Name for the saved playlist.

# --- Presets ---

- id: list_presets
  label: List Presets
  kind: action
  endpoint: "GET /Presets"
  params: []

- id: load_preset
  label: Load Preset
  kind: action
  endpoint: "GET /Preset"
  params:
    - name: id
      type: string
      description: "Preset id number, or +1 for next preset, or -1 for previous preset."

# --- Content Browsing ---

- id: browse
  label: Browse Music Content
  kind: action
  endpoint: "GET /Browse"
  params:
    - name: key
      type: string
      description: "Browse key (URL-encoded). Absent = top-level browse. Value taken from browseKey, nextKey, parentKey, or contextMenuKey attribute of a prior response."
      required: false
    - name: withContextMenuItems
      type: integer
      value: 1
      description: "Always 1 when used. Enables inline context menus in response."
      required: false
    - name: q
      type: string
      description: "Search term. Used with key set to a searchKey value from a prior response."
      required: false

# --- Player Grouping ---

- id: add_slave
  label: Group Player(s) to Primary
  kind: action
  endpoint: "GET /AddSlave"
  params:
    - name: slave
      type: string
      description: IP address of the secondary player to add (single player).
      required: false
    - name: port
      type: integer
      description: Port number of the secondary player (default 11000).
      required: false
    - name: slaves
      type: string
      description: Comma-separated IP addresses of secondary players (for multiple).
      required: false
    - name: ports
      type: string
      description: Comma-separated port numbers of secondary players (for multiple).
      required: false
    - name: group
      type: string
      description: Optional group name. If not provided, BluOS assigns a default name.
      required: false

- id: remove_slave
  label: Remove Player(s) from Group
  kind: action
  endpoint: "GET /RemoveSlave"
  params:
    - name: slave
      type: string
      description: IP address of the secondary player to remove (single player).
      required: false
    - name: port
      type: integer
      description: Port of the secondary player to remove.
      required: false
    - name: slaves
      type: string
      description: Comma-separated IP addresses of secondary players to remove (multiple).
      required: false
    - name: ports
      type: string
      description: Comma-separated port numbers of secondary players to remove (multiple).
      required: false

# --- Input Selection ---

- id: select_active_input
  label: Select Active Input Source
  kind: action
  endpoint: "GET /Play"
  params:
    - name: url
      type: string
      description: "URL attribute from /RadioBrowse?service=Capture response (URL-encoded)."
  notes: "Supported input types include Bluetooth, Analog, Optical, HDMI ARC, Phono, etc. Hub inputs supported."

- id: select_external_input_by_index
  label: Select External Input by Index (firmware <4.2.0)
  kind: action
  endpoint: "GET /Play"
  params:
    - name: inputIndex
      type: integer
      description: "Index (1-based, excluding Bluetooth) of inputs from /Settings?id=capture&schemaVersion=32 response."
  notes: "For BluOS firmware newer than v3.8.0 and older than v4.2.0."

- id: select_external_input_by_type
  label: Select External Input by Type (firmware >=4.2.0)
  kind: action
  endpoint: "GET /Play"
  params:
    - name: inputTypeIndex
      type: string
      description: "Input type-index string (e.g., spdif-1, analog-1, bluetooth-1, arc-1, earc-1, phono-1, coax-1, computer-1, aesebu-1, balanced-1, microphone-1)."
  notes: "For BluOS firmware v4.2.0 or newer."

# --- Bluetooth Mode ---

- id: set_bluetooth_mode
  label: Set Bluetooth Mode
  kind: action
  endpoint: "GET /audiomodes"
  params:
    - name: bluetoothAutoplay
      type: integer
      range: "0|1|2|3"
      description: "0 = Manual, 1 = Automatic, 2 = Guest, 3 = Disabled."
  notes: "No response body returned."

# --- Reboot ---

- id: reboot
  label: Reboot Player
  kind: action
  endpoint: "POST /reboot"
  params:
    - name: yes
      type: string
      description: Any value (e.g., 1). Required to trigger reboot.
  notes: "Uses HTTP POST. Response is plain text: 'Settings Updated / Rebooting. Please close this window. / Please wait...'"

# --- Doorbell ---

- id: doorbell_play
  label: Play Doorbell Chime
  kind: action
  endpoint: "GET /Doorbell"
  params:
    - name: play
      type: integer
      value: 1
      description: Always 1 to play doorbell chime.

Feedbacks

# --- Playback Status (/Status) ---

- id: playback_status
  label: Playback Status
  endpoint: "GET /Status"
  type: xml
  notes: "Supports long polling with timeout and etag parameters. Polling limit: at most one request every 30 seconds without long-polling; at least 1 second between consecutive long-poll requests."
  attributes:
    - name: etag
      type: string
      description: Opaque value for long-polling change detection (root element attribute).
    - name: state
      type: enum
      values: [play, pause, stop, stream, connecting]
      description: Current player playback state.
    - name: volume
      type: integer
      range: "-1..100"
      description: "Volume level (0–100); -1 means fixed volume."
    - name: db
      type: number
      description: Volume level in dB.
    - name: mute
      type: integer
      range: "0|1"
      description: "1 if muted, 0 if not muted."
    - name: muteVolume
      type: integer
      description: Unmuted volume level (0–100) when muted.
    - name: muteDb
      type: number
      description: Unmuted volume in dB when muted.
    - name: title1
      type: string
      description: First line of now-playing metadata (MUST be used for UI display).
    - name: title2
      type: string
      description: Second line of now-playing metadata.
    - name: title3
      type: string
      description: Third line of now-playing metadata.
    - name: artist
      type: string
    - name: album
      type: string
    - name: name
      type: string
      description: Title of current playing audio track.
    - name: shuffle
      type: integer
      range: "0|1"
      description: "0 = off, 1 = on."
    - name: repeat
      type: integer
      range: "0|1|2"
      description: "0 = repeat queue, 1 = repeat track, 2 = repeat off."
    - name: totlen
      type: integer
      description: Total length of current track in seconds.
    - name: secs
      type: integer
      description: Seconds played of current track (not included in etag calculation; client must increment independently).
    - name: canSeek
      type: integer
      range: "0|1"
      description: "1 if scrubbing is possible via /Play?seek=."
    - name: canMovePlayback
      type: boolean
      description: True if playback can be moved to another player.
    - name: service
      type: string
      description: Service id of current audio.
    - name: serviceIcon
      type: string
      description: URL of current service icon.
    - name: image
      type: string
      description: URL of artwork for current audio.
    - name: quality
      type: string
      description: "Audio quality: cd, hd, dolbyAudio, mqa, mqaAuthored, or numeric bitrate."
    - name: pid
      type: integer
      description: Unique play queue id.
    - name: prid
      type: integer
      description: Unique preset id.
    - name: syncStat
      type: integer
      description: Changes whenever /SyncStatus response changes.
    - name: sleep
      type: string
      description: Minutes remaining before sleep timer activates.
    - name: streamUrl
      type: string
      description: "If present, indicates play queue is not the audio source; shuffle/repeat/skip/back not relevant."
    - name: groupName
      type: string
      description: Group name (primary player only).
    - name: groupVolume
      type: number
      description: Group volume level (primary player only).
    - name: actions
      type: xml_element
      description: Available streaming radio actions (back, skip, love, ban) as <action> elements.

# --- Sync Status (/SyncStatus) ---

- id: sync_status
  label: Player and Group Sync Status
  endpoint: "GET /SyncStatus"
  type: xml
  notes: "Supports long polling. Recommended polling interval: 180 seconds."
  attributes:
    - name: volume
      type: integer
      range: "-1..100"
      description: "Volume level; -1 = fixed."
    - name: db
      type: number
      description: Volume level in dB.
    - name: mute
      type: integer
      range: "0|1"
    - name: muteVolume
      type: integer
    - name: muteDb
      type: number
    - name: name
      type: string
      description: Player name.
    - name: model
      type: string
    - name: modelName
      type: string
    - name: brand
      type: string
    - name: group
      type: string
      description: Group name.
    - name: id
      type: string
      description: Player IP and port.
    - name: mac
      type: string
      description: Player unique network id (may be MAC address).
    - name: initialized
      type: boolean
      description: True if player is set up; false if setup required via BluOS Controller app.
    - name: master
      type: xml_element
      description: Primary player IP (only if this player is secondary). Attributes: port, reconnecting.
    - name: slave
      type: xml_element
      description: Secondary player IPs (only if this player is primary). May be multiple.
    - name: syncStat
      type: integer
    - name: zone
      type: string
      description: Name of fixed group.
    - name: zoneMaster
      type: boolean
    - name: zoneSlave
      type: boolean
    - name: etag
      type: string

# --- Volume Response (/Volume) ---

- id: volume_state
  label: Volume State
  endpoint: "GET /Volume"
  type: xml
  attributes:
    - name: volume
      type: integer
      range: "-1..100"
      description: "Current volume (0..100); -1 = fixed."
    - name: db
      type: number
    - name: mute
      type: integer
      range: "0|1"
    - name: muteDb
      type: number
    - name: muteVolume
      type: integer
    - name: etag
      type: string

# --- Doorbell Response ---

- id: doorbell_status
  label: Doorbell Chime Status
  endpoint: "GET /Doorbell"
  type: xml
  attributes:
    - name: enable
      type: integer
      description: Indicates chime is enabled.
    - name: volume
      type: integer
      description: Chime volume.
    - name: chime
      type: string
      description: Chime audio path.

Variables

# UNRESOLVED: no settable parameters beyond discrete actions found in source

Events

# Long-poll unsolicited notifications via etag change detection on /Status and /SyncStatus.
# No push/subscribe mechanism described in source.
# UNRESOLVED: no out-of-band event push protocol found in source

Macros

# UNRESOLVED: no multi-step sequences explicitly described in source as macros

Safety

confirmation_required_for:
  - reboot  # reboot command causes service interruption; confirmation recommended
interlocks: []
# UNRESOLVED: no safety warnings or interlock procedures stated in source beyond standard reboot caution

Notes

Port discovery: Port 11000 is the default for all BluOS players. The CI580 four-node chassis uses ports 11000, 11010, 11020, 11030 for nodes 1–4. Actual port should be discovered via mDNS (services musc._tcp and musp._tcp) or the proprietary LSDP protocol (UDP broadcast on port 11430).

Long-polling: The API supports long-polling on /Status and /SyncStatus. Without long-polling, clients must restrict polling to at most one request every 30 seconds. With long-polling, consecutive requests for the same resource must be at least 1 second apart. Recommended timeout for /Status long-poll: 100 seconds; for /SyncStatus: 180 seconds.

Secondary player proxying: When a player is a secondary (slave) in a group, many requests directed to it are internally proxied to the primary player. This includes /Status, playback control, play queue, and content browsing requests.

secs field: The secs field in /Status is not included in the etag calculation. Clients must increment the playback position themselves based on elapsed time when state is play or stream.

streamUrl flag: If <streamUrl> is present in /Status, the play queue is not the audio source; shuffle, repeat, skip, and back are not relevant.

title1/title2/title3 display rule: These MUST be used for three-line now-playing UI. Do not use album, artist, or name directly. If twoline_title1/twoline_title2 are present they MUST be used for two-line UI.

Image redirects: Image URLs beginning with /Artwork may result in HTTP redirects. Add followRedirects=1 parameter when fetching to avoid redirect handling.

Browse key encoding: All key parameter values in /Browse requests must be URL-encoded (percent-escaped). browseKey, contextMenuKey, and searchKey attribute values must always be URI-encoded when used as key parameters.

LSDP discovery: The Lenbrook Service Discovery Protocol uses UDP broadcast on port 11430 (IANA-registered). Class IDs: 0x0001 = BluOS Player, 0x0003 = BluOS Player (secondary in multi-zone), 0x0008 = BluOS Hub. Packet header magic word is ASCII "LSDP". Announce messages broadcast approximately every minute at steady state.

API version: Source document is BluOS Custom Integration API Version 1.7.

Provenance

source_domains:
  - bluos.io
source_urls:
  - https://bluos.io/wp-content/uploads/2025/06/BluOS-Custom-Integration-API_v1.7.pdf
retrieved_at: 2026-05-16T18:38:12.112Z
last_checked_at: 2026-06-02T21:54:09.041Z

Verification Summary

verdict: verified
checked_at: 2026-06-02T21:54:09.041Z
matched_actions: 29
action_count: 29
confidence: medium
summary: "All 29 spec actions traced to BluOS volume control API. Comprehensive volume management with individual and group control confirmed. (9 unresolved item(s) noted in Known Gaps.)"

Known Gaps

- "authentication mechanism not described in source — no login procedure found"
- "no settable parameters beyond discrete actions found in source"
- "no out-of-band event push protocol found in source"
- "no multi-step sequences explicitly described in source as macros"
- "no safety warnings or interlock procedures stated in source beyond standard reboot caution"
- "authentication not described — assume no auth required but not explicitly confirmed for all environments"
- "HTTPS support not mentioned; all examples use plain HTTP"
- "error response format for HTTP-level errors (4xx/5xx) not documented"
- "firmware version compatibility for volume/playback endpoints not stated (only input selection endpoints reference firmware versions)"

From the AI4AV catalog (https://ai4av.net) · ODbL-1.0