连接与配网
Music Assistant / Home Assistant 连接操作手册
版本: v1.9-ma-ha 日期: 2026-08-25 适用设备: KABU Speaker (ESP32-S3)
本文档详细记录 Music Assistant (MA) 和 Home Assistant (HA) 与 KABU 设备的连接过程,作为标准操作手册使用。
目录
1. 前置准备
1.1 环境要求
| 组件 | 版本/要求 | 说明 |
|---|---|---|
| Docker Desktop | 4.87.0+ | 数据盘迁移至 E:\docker-data |
| Music Assistant | 2.9.13 | aiosendspin 必须 6.0.5 |
| Home Assistant | stable | 内部 URL 必须配置为宿主机 LAN IP |
| KABU 固件 | v1.9-ma-ha | 支持 legacy 明文方言自动协商 |
| 网络 | 同一局域网 | 设备与宿主机互通 |
1.2 端口映射(docker-compose.yml)
services:
homeassistant:
image: ghcr.io/home-assistant/home-assistant:stable
ports:
- "8123:8123" # Web UI / API
- "14000:14000" # DLNA GENA 事件回调(必需)
volumes:
- ./home-assistant:/config
musicassistant:
image: ghcr.io/music-assistant/server:latest
ports:
- "8095:8095" # Web UI / API
volumes:
- ./music-assistant:/data
- ./music:/music
1.3 启动服务
cd E:\ha-ma-env
docker compose up -d
docker compose ps
验证访问:
- HA: <http://localhost:8123>(admin / KabuHA2026!)
- MA: <http://localhost:8095>(admin / KabuMA2026!)
2. Music Assistant 连接 Sendspin 播放器
2.1 设备端准备
步骤 1: 切换设备到 sendspin 模式
# 查询当前模式
curl -s http://<设备IP>/api/device/mode | jq '.mode, .boot_profile'
# 切换到 sendspin 模式(设备会重启)
curl -X POST http://<设备IP>/api/device/mode \
-H "Content-Type: application/json" \
-d '{"mode":"sendspin"}'
等待 30-60 秒设备重启完成。
步骤 2: 验证设备状态
# 检查设备模式
curl -s http://<设备IP>/api/device/mode | jq '.mode, .phase'
# 期望输出: "sendspin", "active"
# 检查 Sendspin 播放器状态
curl -s http://<设备IP>/api/sendspin/player | jq '.server_connected, .time_synced, .stream_active'
# 初始状态: false, false, false
步骤 3: 确认 mDNS 广播(可选)
# 在宿主机执行(需要 python-zeroconf)
python -c "from zeroconf import Zeroconf, ServiceBrowser; import time, socket
class L:
def add_service(self, z, t, n):
i = z.get_service_info(t, n)
if i and '_sendspin' in t:
print(f'Found: {n} at {[socket.inet_ntoa(a) for a in i.addresses]}:{i.port}')
def remove_service(self,*a): pass
def update_service(self,*a): pass
z = Zeroconf()
b = ServiceBrowser(z, '_sendspin._tcp.local.', L())
time.sleep(5)
z.close()"
期望输出:
Found: 3CDC75F8E1F8@KABU._sendspin._tcp.local. at ['192.168.1.67']:8928
2.2 MA 端配置
步骤 4: 添加 Sendspin 播放器(手动 IP)
- 打开 MA Web UI: <http://localhost:8095>
- 进入 Settings → Players
- 点击 + Add player manually
- 输入设备 IP(如
192.168.1.67) - 点击 Save
注意: 容器内 mDNS 不可用(Windows 10 无 mirrored 网络),必须手动添加。
步骤 5: 等待自动连接
MA 会自动尝试连接设备,过程如下:
第一次连接尝试(spec 模式):
- MA 发送
client/init(spec 规范握手) - 设备回复
server/init+ Noise 握手请求 - MA (aiosendspin 6.0.5) 不理解
client/init,断开连接 - MA 日志:
ClientMessage has no subtype with attribute 'type' equal to 'client/init'
第二次连接尝试(spec 模式):
- 重复第一次,失败
- 设备固件记录该 IP 的失败次数 = 2
第三次连接尝试(legacy 模式,自动激活):
- 设备检测到该 IP 连续失败 2 次,切换为 legacy 明文方言
- MA 发送
client/hello(明文 JSON) - 设备回复
server/hello(明文 JSON,包含active_roles) - 握手成功,进入 SESSION_ACTIVE
步骤 6: 验证连接状态
检查 MA 日志:
docker logs musicassistant --tail 50 | grep -i "sendspin\|kabu"
期望输出:
Player (type protocol) registered: M2m1UBZEY0WOY7_.../KABU
Creating universal player upm2m1ubzey0woy7_gacblzcjlzckbjf5ub_pamt7uwsg with protocol players: ['M2m1UBZEY0WOY7_GAcbLZCJLZCKbjf5uB_pAMt7uWSg']
检查设备状态:
curl -s http://<设备IP>/api/sendspin/player | jq '.'
期望输出:
{
"role": "member",
"server_connected": true,
"time_synced": true,
"stream_active": false,
"server_name": "Music Assistant",
"session_owner": "music_assistant_external",
"volume": 50,
"muted": false,
"sample_rate": 48000,
"chunks_received": 0,
"chunks_dropped_late": 0,
"underruns": 0
}
关键指标:
server_connected: true- 连接成功time_synced: true- 时钟同步完成stream_active: false- 未播放(等待音频)
2.3 播放测试
步骤 7: 添加音乐源
- MA Web UI → Settings → Providers
- 点击 + Add provider
- 选择 Local Files
- 配置路径:
/music - 点击 Save
将音频文件放入 E:\ha-ma-env\music\ 目录。
步骤 8: 播放音频
- MA Web UI → Music Library
- 选择本地文件(如
kabu_test_tone.wav) - 点击播放按钮
- 选择输出设备: KABU
步骤 9: 验证播放状态
MA 端:
- 播放控制栏显示进度
- 音量控制可用
设备端:
curl -s http://<设备IP>/api/sendspin/player | jq '.stream_active, .chunks_received, .underruns'
期望输出:
true
2849
0
stream_active: true- 正在接收音频流chunks_received- 累计接收音频块数underruns: 0- 无缓冲区欠载(播放流畅)
音频输出:设备应播放音乐,可通过 DAC 听到声音。
步骤 10: 控制测试
暂停/恢复:
- MA 点击暂停按钮
- 设备状态变为
stream_active: false - MA 点击播放按钮
- 设备状态恢复为
stream_active: true
音量调节:
# 查看当前音量
curl -s http://<设备IP>/api/sendspin/player | jq '.volume'
# MA 调节音量到 30
# 验证设备音量同步
curl -s http://<设备IP>/api/sendspin/player | jq '.volume'
# 期望输出: 30
3. Home Assistant 连接 DLNA 渲染器
3.1 设备端准备
步骤 1: 切换设备到 dlna 模式
# 切换到 dlna 模式(设备会重启)
curl -X POST http://<设备IP>/api/device/mode \
-H "Content-Type: application/json" \
-d '{"mode":"dlna"}'
等待 30-60 秒设备重启完成。
步骤 2: 验证 DLNA 服务
# 检查设备模式
curl -s http://<设备IP>/api/device/mode | jq '.mode, .phase'
# 期望输出: "dlna", "active"
# 获取 DLNA 设备描述
curl -s http://<设备IP>:49152/rootDesc.xml | head -20
期望输出(XML 格式):
<?xml version="1.0"?>
<root xmlns="urn:schemas-upnp-org:device-1-0">
<specVersion><major>1</major><minor>0</minor></specVersion>
<device>
<deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType>
<friendlyName>KABU</friendlyName>
<manufacturer>KABU</manufacturer>
<modelName>KABU</modelName>
<modelNumber>1.9</modelNumber>
...
</device>
</root>
3.2 HA 端配置
步骤 3: 配置 HA 内部 URL
- 打开 HA Web UI: <http://localhost:8123>
- 进入 Settings → System → Network
- 找到 Home Assistant URL
- 设置 Internal URL:
http://192.168.1.32:8123(替换为你的宿主机 LAN IP) - 点击 Save
重要: 必须配置为宿主机 LAN IP,否则设备无法访问 HA 媒体文件。
步骤 4: 添加 DLNA Digital Media Renderer 集成
- 进入 Settings → Devices & Services
- 点击 + ADD INTEGRATION
- 搜索 DLNA Digital Media Renderer
- 选择 Manual configuration
- 输入 URL:
http://<设备IP>:49152/rootDesc.xml - 点击 Submit
等待 HA 发现设备并创建 media_player.kabu 实体。
步骤 5: 配置 DLNA 集成选项(必需)
- 进入 Settings → Devices & Services → DLNA Digital Media Renderer
- 找到 KABU 设备
- 点击 CONFIGURE(齿轮图标)
- 设置以下选项:
| 选项 | 值 | 说明 |
|---|---|---|
| Listen port | 14000 | 容器发布的端口 |
| Callback URL override | http://192.168.1.32:14000/notify | 宿主机 LAN IP + 端口 |
- 点击 Save
关键: 不配置回调会导致 pause/stop 功能缺失、音量状态不更新。
步骤 6: 验证集成
- 进入 Settings → Devices & Services → DLNA Digital Media Renderer → KABU
- 查看设备信息:
- 状态:
idle或playing - 支持的控件: Play, Pause, Stop, Volume
- 进入 Developer Tools → States
- 搜索
media_player.kabu - 查看属性:
friendly_name: KABU
supported_features: 135693 # 包含 PAUSE (1)
volume_level: 0.5
is_volume_muted: false
3.3 播放测试
步骤 7: 准备媒体文件
将音频文件放入 E:\ha-ma-env\home-assistant\media\ 目录。
例如:kabu_test_tone.wav(30 秒 44.1kHz 正弦波)
步骤 8: 通过 Developer Tools 播放
- 进入 Developer Tools → Services
- 选择服务:
media_player.play_media - 填写参数:
entity_id: media_player.kabu
media_content_id: media-source://media_source/local/kabu_test_tone.wav
media_content_type: music
- 点击 CALL SERVICE
步骤 9: 验证播放状态
HA 端:
- 进入 Developer Tools → States
- 搜索
media_player.kabu - 查看状态:
state: playing
attributes:
media_content_id: http://192.168.1.32:8123/media/local/kabu_test_tone.wav?authSig=...
media_content_type: music
media_title: Home Assistant
media_position: 15 # 当前播放位置(秒)
volume_level: 0.5
设备端:
- 音频输出(DAC)播放音乐
- 可通过
curl http://<设备IP>/api/dlna/status查看状态
控制测试:
暂停:
# Developer Tools → Services
Service: media_player.media_pause
entity_id: media_player.kabu
验证:
- HA 状态变为
paused - 设备停止播放
恢复:
Service: media_player.media_play
entity_id: media_player.kabu
验证:
- HA 状态恢复为
playing - 设备继续播放
音量调节:
Service: media_player.volume_set
entity_id: media_player.kabu
volume_level: 0.3
验证:
- HA
volume_level变为0.3 - 设备音量同步变化
停止:
Service: media_player.media_stop
entity_id: media_player.kabu
验证:
- HA 状态变为
idle - 设备停止播放
3.4 GENA 事件验证(高级)
如需验证 DLNA 事件订阅正常工作:
# 在宿主机启动 GENA 探针(已提供 gena_probe.py)
python E:\ha-ma-env\gena_probe.py
期望输出:
SUBSCRIBE: 200 uuid:... Second-300
SetAVTransportURI -> 200
Play -> 200
Stop -> 200
NOTIFY from ('<设备IP>', <port>)
...
TOTAL_NOTIFIES: 3
4. 设备模式切换
4.1 模式说明
| 模式 | 用途 | 适用场景 |
|---|---|---|
sendspin | Music Assistant 播放器 | MA 投送音乐 |
dlna | Home Assistant DLNA 渲染器 | HA 投送音乐 |
airplay | AirPlay 接收器 | iPhone/Mac 投送 |
radio | 网络收音机 | 独立播放 |
4.2 切换命令
# 查询当前模式
curl -s http://<设备IP>/api/device/mode | jq '.mode, .boot_profile'
# 切换到指定模式(设备会重启)
curl -X POST http://<设备IP>/api/device/mode \
-H "Content-Type: application/json" \
-d '{"mode":"<mode>"}'
示例:
# 切换到 sendspin 模式(用于 MA)
curl -X POST http://192.168.1.67/api/device/mode \
-H "Content-Type: application/json" \
-d '{"mode":"sendspin"}'
# 切换到 dlna 模式(用于 HA)
curl -X POST http://192.168.1.67/api/device/mode \
-H "Content-Type: application/json" \
-d '{"mode":"dlna"}'
4.3 重启等待
设备切换模式后会重启,需要等待:
- 重启时间: 约 30-60 秒
- 验证命令:
# 循环检查直到 phase 变为 active
while true; do
phase=$(curl -s http://<设备IP>/api/device/mode | jq -r '.phase')
if [ "$phase" = "active" ]; then
echo "Device ready"
break
fi
sleep 5
done
5. 排错指南
5.1 MA 连接失败
问题: MA 无法发现设备
症状:
- MA Players 列表中没有 KABU
- 手动添加 IP 后仍不显示
排查步骤:
- 确认设备模式:
curl -s http://<设备IP>/api/device/mode | jq '.mode'
# 必须是 "sendspin"
- 检查网络连接:
# 宿主机 ping 设备
ping <设备IP>
# 检查端口
curl -s http://<设备IP>:8928/ || echo "Port 8928 not reachable"
- 检查 MA 日志:
docker logs musicassistant --tail 50 | grep -i "sendspin\|error"
- 重启 MA 容器:
docker restart musicassistant
问题: MA 连接后立即断开
症状:
- MA 日志显示
Unexpected error inside websocket API - 设备短暂连接后断开
原因: aiosendspin 版本不兼容
解决:
# 检查版本
docker exec musicassistant /app/venv/bin/pip show aiosendspin | grep Version
# 如果版本不是 6.0.5,强制降级
docker exec musicassistant /app/venv/bin/uv pip install "aiosendspin==6.0.5"
docker restart musicassistant
问题: MA 连接后无音频输出
症状:
- MA 显示播放器已连接
- 播放时无声音
排查步骤:
- 检查设备 stream_active:
curl -s http://<设备IP>/api/sendspin/player | jq '.stream_active, .chunks_received'
- 播放时
stream_active应为true chunks_received应递增
- 检查时钟同步:
curl -s http://<设备IP>/api/sendspin/player | jq '.time_synced'
- 必须为
true
- 检查 underruns:
curl -s http://<设备IP>/api/sendspin/player | jq '.underruns'
- 应为
0或很小值 - 如果持续增长,表示网络问题
- 检查 DAC 输出:
- 确认 DAC 硬件连接正常
- 检查设备日志是否有音频输出错误
5.2 HA 连接失败
问题: HA 无法发现 DLNA 设备
症状:
- DLNA 集成中没有发现设备
- 手动添加后实体不可用
排查步骤:
- 确认设备模式:
curl -s http://<设备IP>/api/device/mode | jq '.mode'
# 必须是 "dlna"
- 检查 DLNA 服务:
curl -s http://<设备IP>:49152/rootDesc.xml
# 应返回 XML
- 检查 HA 日志:
docker logs homeassistant --tail 50 | grep -i "dlna\|upnp"
- 重新添加集成:
- Settings → Devices & Services
- 删除旧的 DLNA 集成
- 重新添加
问题: Pause/Stop 功能不可用
症状:
- HA 显示媒体播放器,但没有暂停按钮
- 调用
media_pause服务失败
原因: GENA 事件回调未配置
解决:
- 确认 docker-compose.yml 发布了 14000 端口
- 确认 DLNA 集成选项:
- Listen port:
14000 - Callback URL override:
http://<宿主机LAN IP>:14000/notify
- 重新配置集成
问题: 音量状态不更新
症状:
- 调节音量后,HA 显示的
volume_level不变化
原因: 同 Pause/Stop 问题
解决: 配置 GENA 事件回调(见上)
问题: 播放媒体时设备返回 404
症状:
- 调用
play_media成功 - 设备不播放
- 设备日志显示 HTTP 404
原因: HA 内部 URL 配置错误
解决:
- 确认 HA Settings → System → Network → Internal URL
- 必须是
http://<宿主机LAN IP>:8123(不是 localhost 或 127.0.0.1) - 重新配置后重启 HA:
docker restart homeassistant
5.3 通用问题
问题: 容器启动失败
症状:
docker compose up报错- 容器反复重启
排查:
# 查看容器日志
docker compose logs
# 检查端口占用
netstat -an | grep -E "8123|8095|14000"
# 检查 Docker 状态
docker compose ps
问题: 设备重启后 MA 需要重新连接
症状:
- 设备重启后 MA 播放器显示离线
- 需要等待一段时间才自动重连
原因: 设备重启会清除 legacy 方言记忆(RAM 态)
正常行为:
- MA 会自动重试连接
- 前两次尝试走 spec 模式(失败)
- 第三次起自动切换 legacy 模式(成功)
- 整个过程约 3-5 秒
如需加速: 重启 MA 容器重置重连计数器
6. 技术参考
6.1 Sendspin 协议握手流程(Legacy 模式)
MA (aiosendspin 6.0.5) KABU 设备 (v1.9-ma-ha)
| |
| 1. WebSocket Connect |
|---------------------------------------->|
| |
| 2. client/hello (明文 JSON) |
| { |
| "client_id": "...", |
| "name": "KABU", |
| "version": 1, |
| "supported_roles": ["player@v1"], |
| "player_support": {...} |
| } |
|---------------------------------------->|
| |
| 3. server/hello (明文 JSON) |
| { |
| "server_id": "...", |
| "name": "Music Assistant", |
| "version": 1, |
| "active_roles": ["player@v1"] |
| } |
|<----------------------------------------|
| |
| 4. 进入 SESSION_ACTIVE |
| 开始明文 JSON 消息交换 |
| |
| 5. stream/start (明文) |
|<----------------------------------------|
| |
| 6. 二进制音频帧 (type=4 + 时间戳) |
|<----------------------------------------|
| (重复) |
6.2 DLNA AVTransport 状态机
Play
STOPPED -----------------> PLAYING
^ |
| Stop | Pause
| v
| PAUSED_PLAYBACK
| |
^ | Stop
| v
+--------------------- STOPPED
设备状态查询:
curl -s http://<设备IP>/api/dlna/status | jq '.transport_state'
6.3 关键 API 端点
设备端
| 端点 | 方法 | 说明 |
|---|---|---|
/api/device/mode | GET | 查询当前模式 |
/api/device/mode | POST | 切换模式 |
/api/sendspin/player | GET | Sendspin 播放器状态 |
/api/sendspin/leader | GET | Sendspin 领导者状态 |
/api/dlna/status | GET | DLNA 渲染器状态 |
/api/system/info | GET | 系统信息 |
:49152/rootDesc.xml | GET | DLNA 设备描述 |
HA 端
| 服务 | 参数 | 说明 |
|---|---|---|
media_player.play_media | entity_id, media_content_id, media_content_type | 播放媒体 |
media_player.media_pause | entity_id | 暂停 |
media_player.media_play | entity_id | 播放 |
media_player.media_stop | entity_id | 停止 |
media_player.volume_set | entity_id, volume_level (0.0-1.0) | 设置音量 |
MA 端
通过 Web UI 操作,无直接 API 文档。
6.4 日志查看
# MA 日志
docker logs musicassistant --tail 100
# HA 日志
docker logs homeassistant --tail 100
# 过滤 Sendspin 相关
docker logs musicassistant | grep -i sendspin
# 过滤 DLNA 相关
docker logs homeassistant | grep -i dlna
# 实时监控
docker logs -f musicassistant
docker logs -f homeassistant
6.5 性能指标
Sendspin 播放器:
curl -s http://<设备IP>/api/sendspin/player | jq '{
connected: .server_connected,
synced: .time_synced,
streaming: .stream_active,
chunks: .chunks_received,
dropped: .chunks_dropped_late,
underruns: .underruns
}'
健康标准:
connected: truesynced: truedropped: 0(或极小)underruns: 0(播放时)
6.6 已知限制
- 容器内 mDNS 不可用
- Windows 10 无 mirrored 网络
- 必须手动添加播放器/集成
- aiosendspin 版本锁定 6.0.5
- MA 2.9.13 代码不兼容 9.x API
- 升级会导致 Sendspin provider 加载失败
- 海外流媒体超时
- 容器 NAT 网络下 RFC1918 源地址被部分 CDN 屏蔽
- 本地文件/NAS/国内源不受影响
- 设备重启清除 legacy 记忆
- 重连需重新探测(自动,3-5 秒)
- 如需持久化可写 NVS(未实现)
- HA DLNA media_duration 恒为 0
- 设备 WAV/流时长上报限制
- HA 用本地估算推进位置
附录 A: 快速参考卡
MA 连接检查清单
- [ ] 设备模式 =
sendspin - [ ] 设备 phase =
active - [ ] MA aiosendspin = 6.0.5
- [ ] MA Players 中添加设备 IP
- [ ] 设备
server_connected: true - [ ] 设备
time_synced: true
HA 连接检查清单
- [ ] 设备模式 =
dlna - [ ] 设备 phase =
active - [ ] HA Internal URL = 宿主机 LAN IP
- [ ] DLNA 集成 URL =
http://<设备IP>:49152/rootDesc.xml - [ ] DLNA Listen port =
14000 - [ ] DLNA Callback URL =
http://<宿主机LAN IP>:14000/notify - [ ]
media_player.kabu实体存在 - [ ]
supported_features包含 PAUSE (1)
常用命令速查
# 启动服务
cd E:\ha-ma-env && docker compose up -d
# 查看状态
docker compose ps
curl -s http://192.168.1.67/api/device/mode | jq
# 切换模式
curl -X POST http://192.168.1.67/api/device/mode -H "Content-Type: application/json" -d '{"mode":"sendspin"}'
curl -X POST http://192.168.1.67/api/device/mode -H "Content-Type: application/json" -d '{"mode":"dlna"}'
# 查看播放器状态
curl -s http://192.168.1.67/api/sendspin/player | jq
curl -s http://192.168.1.67/api/dlna/status | jq
# 查看日志
docker logs -f musicassistant
docker logs -f homeassistant
文档结束
如有问题,请参考:
- 部署指南:
docs/ma_ha_cast_environment.md - 互操作报告:
docs/ma_ha_interop_report.md