Technical docs

Developer Documentation

DJConnect is a Home Assistant-first platform for Spotify or Music Assistant playback, voice remote control, Ask DJ, OTA, pairing and client integrations.

Home Assistant is the orchestration point

The custom integration coordinates pairing, backend playback, Assist/STT/TTS, Ask DJ, Music DNA, diagnostics and firmware update flows. Clients render state and send intent; they do not own Spotify backend credentials.

Architecture overview

Clients
ESP32Device runtime, audio, local UI and OTA target. No Spotify credentials.
iOS, macOS, watchOSHome Assistant API clients with optional Apple push wake/sync hints.
Raspberry Pi, WindowsLocal or desktop clients using DJConnect API contracts.
Home Assistant DJConnect integrationPairing, bearer token validation, Spotify OAuth/backend playback, Assist/STT/TTS, Ask DJ, Music DNA, diagnostics, OTA coordination and status cache.
Backends and services
Spotify Web API / Music AssistantPlayback and library operations through backend adapters.
Home Assistant Assist/STT/TTSVoice pipeline, transcript and spoken responses.
Central API / APNs relayOptional Apple push wake/sync hints with per-install djci_ tokens.
djconnect-firmwarePublic firmware releases and firmware_manifest.json.

Repositories

RepositoryPurposeRuntime/languagePublic roleLink
pcvantol/djconnectHome Assistant custom integration and canonical contracts.Python / Home AssistantOrchestration, API and HACS install source.GitHub
pcvantol/djconnect-appApple clients.Swift / SwiftUIiOS, macOS and watchOS clients.GitHub
pcvantol/djconnect-esp32Embedded firmware source.ESP32 firmwareDevice runtime, UI, audio and local device API.GitHub
pcvantol/djconnect-windowsWindows client.Windows desktop appDesktop client integration.GitHub
pcvantol/djconnect-piRaspberry Pi client.Python / LinuxLocal controller and display client.GitHub
pcvantol/djconnect-websiteProduct website and public docs.Static HTML/CSS/JS, Cloudflare Pages FunctionsWebsite, docs, downloads and operator UI.GitHub
pcvantol/djconnect-apiCentral API and APNs relay.Cloudflare / API serviceOptional Apple push relay and operator contracts.GitHub
pcvantol/djconnect-firmwarePublic firmware release repository.Release assetsFirmware binaries and manifests.GitHub

Client identity and pairing

Canonical client_type values are esp32, ios, macos, watchos, raspberry_pi and windows. The type must match the stable ID prefix.

djconnect-ios-XXXXXXXXXXXX
djconnect-macos-XXXXXXXXXXXX
djconnect-watchos-XXXXXXXXXXXX
djconnect-raspberry-pi-XXXXXXXXXXXX
djconnect-windows-XXXXXXXXXXXX
djconnect-lilygo-t-embed-s3-XXXXXXXXXXXX

Pairing rules

  • ESP32 status and pairing JSON payloads must include client_type: "esp32".
  • Pairing and status use bearer tokens. Token values must never appear in docs, logs or diagnostics.
  • App clients use Home Assistant API endpoints and do not store playback-backend credentials.
  • ESP32 firmware owns device runtime/audio/UI and stores no Spotify credentials.

API documentation

Examples use placeholders only: <HA_TOKEN>, <DEVICE_TOKEN>, <CLIENT_ID>, <DEVICE_ID>, <PAIRING_CODE> and <IMAGE_TOKEN>.

POST /api/djconnect/v1/status

Used by ESP32/local clients to publish current device status to Home Assistant. Auth: bearer device token.

{"client_type":"esp32","device_id":"<DEVICE_ID>","firmware_version":"3.2.16","battery_percent":84}
{"success":true,"paired":true,"server_time":"2026-07-05T08:00:00Z"}

POST /api/djconnect/v1/command

Used by app/device clients for playback, backend-aware actions, Ask DJ Play Now and confirmation responses. Auth: bearer HA/client token.

{"client_type":"ios","client_id":"<CLIENT_ID>","command":"play_track","value":"spotify:track:example"}
{"success":true,"music_backend":"spotify_direct","music_backend_available":true,"music_target_player":"Living Room"}

POST /api/djconnect/v1/voice

Used for voice/PTT upload or text-only DJ response tests. WAV requests use Assist/STT before command or Ask DJ handling. Auth: bearer HA/client token.

{"client_type":"macos","client_id":"<CLIENT_ID>","text":"Play the latest album by Nova Lane"}
{"success":true,"recognized_text":"Play the latest album by Nova Lane","message":"I found a matching album."}

POST /api/djconnect/v1/ask_dj/message

Text chat for iOS, macOS, watchOS, Raspberry Pi and Windows. client_message_id deduplicates retries. Auth: bearer HA/client token.

{"client_type":"watchos","client_id":"<CLIENT_ID>","client_message_id":"msg-001","message":"Why does this track fit my mood?"}
{"success":true,"messages":[{"role":"user","text":"Why does this track fit my mood?"},{"role":"assistant","text":"Because it matches your recent late-night groove."}],"history_revision":42}

GET /api/djconnect/v1/ask_dj/history?since_revision=<number>

Synchronizes server-side HA-user-scoped Ask DJ history to clients. Auth: bearer HA/client token.

{"success":true,"history_revision":42,"messages":[{"role":"assistant","text":"Try a mellow synth mix."}]}

POST /api/djconnect/v1/ask_dj/history/clear

Clears Ask DJ history for the authenticated Home Assistant user scope. Auth: bearer HA/client token.

{"client_type":"macos","client_id":"<CLIENT_ID>"}
{"success":true,"clear_revision":43}

POST /api/djconnect/v1/ask_dj

Developer/service Ask DJ entrypoint for structured requests. Auth: Home Assistant authenticated request.

{"message":"Suggest three quiet tracks","client_type":"macos"}
{"success":true,"text":"Here are three quiet picks.","intent":"personal_music_recommendations"}

POST /api/djconnect/v1/ask_dj/idle_suggestion

Backend-generated Ask DJ suggestion for idle clients that support it. Auth: bearer HA/client token.

{"client_type":"ios","client_id":"<CLIENT_ID>","locale":"en"}
{"success":true,"message":"Want a short discovery mix?"}

POST /api/djconnect/v1/music_dna/profile

Returns structured Music DNA dashboard/profile data. Music DNA is explicit opt-in and server-side in Home Assistant. The profile may include snapshot_history, privacy_dashboard and discovery_feedback; clients do not rebuild Music DNA locally.

{"client_type":"ios","client_id":"<CLIENT_ID>"}
{"success":true,"enabled":true,"profile":{"summary":"Warm electronic listening pattern.","snapshot_history":[],"privacy_dashboard":{"sources":["play_now","discover_feedback"]},"discovery_feedback":{"accepted_recommendations":2}}}

POST /api/djconnect/v1/music_dna/settings

Enables or disables Music DNA for the HA user scope. Auth: bearer HA/client token.

{"client_type":"macos","enabled":true}
{"success":true,"enabled":true}

POST /api/djconnect/v1/music_dna/clear

Clears learned Music DNA while preserving the opt-in setting. Auth: bearer HA/client token.

{"client_type":"macos","confirm":true}
{"success":true,"enabled":true,"cleared":true}

POST /api/djconnect/v1/music_dna/export
POST /api/djconnect/v1/music_dna/import

HTTP-only Music DNA import/export helpers. Do not expose them as websocket commands and do not place raw OAuth tokens, bearer tokens, raw audio, full prompts or full listening history in exported material.

{"client_type":"macos","client_id":"<CLIENT_ID>"}
{"success":true,"format":"djconnect_music_dna_export_v1"}

GET /api/djconnect/v1/music_discovery

Returns backend-owned Music Discovery recommendations from Home Assistant Music DNA. Discover is not a recently-played list; raw recently played tracks are not cards unless returned explicitly in sections[]. Clients render backend section order and do not hardcode section ids.

{"client_type":"ios","client_id":"<CLIENT_ID>"}
{"success":true,"enabled":true,"sections":[{"id":"new_for_you","items":[{"id":"rec-001","kind":"track","title":"Midnight Circuit","reason":"Fits your recent late-night groove.","reason_sources":["music_dna","spotify_top_profile"],"quality_score":0.91,"quality_band":"high","quality_factors":["fresh_artist","mood_match"]}]}]}

POST /api/djconnect/v1/music_discovery/refresh

Refreshes the Home Assistant-generated discovery feed. The backend also refreshes roughly hourly while Music DNA is enabled, and may rebuild after new profile data, mood, Play Now or negative feedback. Clients never render recommendations from push payloads.

{"client_type":"macos","client_id":"<CLIENT_ID>"}
{"success":true,"refresh_target":"music_discovery"}

POST /api/djconnect/v1/music_discovery/play

Starts a backend-owned recommendation through its section and item id, instead of generic local playback. Auth: bearer HA/client token.

{"client_type":"ios","section_id":"daily","discovery_item_id":"rec-001"}
{"success":true,"command":"play_now"}

POST /api/djconnect/v1/music_discovery/feedback

Stores negative Discover feedback as compact Music DNA signal. Supported values are not_for_me, less_like_this and hide_artist. Clients keep no permanent local blocklist.

{"client_type":"ios","section_id":"new_for_you","discovery_item_id":"rec-001","feedback":"less_like_this"}
{"success":true,"stored":true}

WebSocket djconnect/capabilities

Clients infer support from capabilities, not Home Assistant version parsing. Responses may include features and fallbacks. If websocket commands are missing, use HTTP fallback paths; if optional features are missing, hide controls such as negative feedback. Music DNA import/export remains HTTP-only.

{"type":"djconnect/capabilities","client_type":"ios"}
{"success":true,"features":{"music_discovery_feedback":true},"fallbacks":{"music_dna_import_export":"http_only"}}

GET /api/djconnect/v1/image_proxy/{token}

Serves external Ask DJ images through a safe proxy token. Auth: endpoint token plus Home Assistant access context.

GET /api/djconnect/v1/image_proxy/<IMAGE_TOKEN>
HTTP 200 image/jpeg

Local device API

Home Assistant uses local-device endpoints for ESP32/Raspberry Pi pairing, commands, OTA and DJ responses. Auth varies by pairing state and device bearer token.

POST /api/device/pair
GET /api/device/info
POST /api/device/command
POST /api/device/ota
POST /api/device/dj_response
{"pairing_code":"<PAIRING_CODE>","device_token":"<DEVICE_TOKEN>"}

Ask DJ contract highlights

  • Ask DJ history is server-side, HA-user scoped and synchronized through history endpoints.
  • messages[] is canonical for render order; client_message_id prevents duplicate chat entries.
  • Responses may include success, text, dj_text, message, messages[], user_message, assistant_message, history_revision, clear_revision, images[], links[], sources[], playback_actions[], confirmation_actions[], intent and action.
  • recently_played_history, track_insight, personal_music_profile_analysis and personal_music_recommendations are informational unless an explicit playback action is executed through /command.
  • External images must go through the image proxy.
  • track_versions_search returns at most 10 Spotify tracks with Play Now actions, requires meaningful title words to match the found title and never starts playback automatically.
  • Discover and Music DNA explanation questions are read-only. Negative preference phrases such as "never play this artist again" are stored only as compact Music DNA avoid signals.

Music Discovery contract highlights

  • Music Discovery is a backend-owned recommendations feed, not a recently-played list.
  • Sections such as new_for_you, rediscover, artist_spotlight and accepted_recommendations must be rendered in backend order.
  • Freshness, dedupe, blocked tracks, live/remix/radio edit/remaster variants, album/title overlap and artist overload are backend-owned.
  • Items carry backend-owned reason, reason_sources, quality_score, quality_band and quality_factors.
  • Clients do not compute local recommendations, reasons, quality scores or permanent blocklists.

Client capability fallback

  • Use djconnect/capabilities and its features/fallbacks fields to decide UI support.
  • Use HTTP fallback when optional websocket commands are not advertised.
  • Hide optional controls, including negative feedback, when the backend does not advertise support.
  • Do not reuse stale artwork from older Ask DJ or Discover responses when a refreshed response omits it.

Music backend architecture

DJConnect routes playback through a use-case/backend layer. Spotify Direct is the default backend; Music Assistant can be used as a backend adapter when configured. New playback/control code should call the backend adapter, not Spotify helpers directly.

music_backend
music_backend_name
music_backend_available
music_backend_revision
music_backend_capabilities
music_target_player
music_backend_error

Firmware / OTA

ESP firmware and the Home Assistant integration must share the same major.minor protocol version. A mismatch returns HTTP 426 with error: "version_mismatch". Public releases expose firmware_manifest.json with firmwares[] entries containing device, asset, url, sha256 and size. The LilyGO device key is lilygo-t-embed-s3; stable uses the latest non-prerelease and beta uses the latest prerelease.

Security and privacy

  • No Spotify credentials on ESP/app clients; Spotify OAuth uses PKCE in Home Assistant.
  • BLE provisioning writes only WiFi SSID/password.
  • Diagnostics redact keys containing token, password, secret, proof, authorization, prompt, history, memory or raw_audio.
  • Push payloads contain no tokens, raw prompts, full history, Music DNA dumps or long assistant text.
  • Music DNA is opt-in. Raw audio is not stored by default.