前段日子为了响应消费降级,就把自认为一直不怎么使用的 Apple Music 给退了。但不知怎么的,自从不能再用 Siri 直接让 HomePod Mini 放歌之后,想要在做咖啡或是洗澡的时候舒适地听歌这个念想突然就日渐强烈起来。

我本身并不是 HomePod 的忠实用户,家里也还有小米之类的其他 Wi-Fi 音箱,回去续订 Apple Music 本身并不能解决全部问题。因此眼下的需求便是以相对便捷的方式在 HomePod、小米音箱这些跨生态的设备上实现统一播放来自 Spotify 或是 Plex 等服务上的音乐。

Music Assistant

Music Assistant 是一个能同时管理离线音乐和聚合在线音乐服务的音乐库管理工具,它可以轻松将音乐流式传输到各种支持的播放器,并与 Home Assistant 高度契合。不久前刚加入了对 Apple Music 的支持,目前已可以用其聚合非常多的音乐服务。

播放器支持方面则对 Airplay、DLNA、Sonos、Google Cast 等常见方案一应俱全。直接使用已经接入 Home Assistant 的播放器自然不在话下,用户还可以透过官方提供的桌面应用 Music Assistant Companion 将 PC 或者 Mac 的扬声器以 Squeezebox (Slimproto) 播放器的形式加入进去以实现更为同步的全屋音乐。

不同传输协议在 Music Assistant 中存在一定差别,对此官方也在文档中提供了很直观的对比图。

我目前所需要接入的 HomePod Mini 和 XiaoMi Sound 均有且仅支持 Airplay 的传输方式(为什么小米不提供 DLNA?),这里就直接省去思考直奔 Airplay 了。

部署

Home Assistant OS 可以很方便地从加载项商店一键安装 Music Assistant,Container 用户则可以根据 Installation/Docker-Image 直接启用一个独立的 Docker 容器从外部接入,毕竟 Music Assistant 本身就是可以脱离 Home Assistant 独立运作的。

docker run -v <dir>:/data --network host --cap-add=DAC_READ_SEARCH --cap-add=SYS_ADMIN --security-opt apparmor:unconfined ghcr.io/music-assistant/server

安装完毕后,打开 Music Assistant 的 WebUI,在 Settings 页面 Add Music Provider 区域分别添加需要集成的音乐服务,根据提示认证并等待扫描入库。

接着 Add Player Provider 选择 Airplay,维持默认设置保存后。来到媒体库找一张喜欢的专辑准备测试刚刚添加完毕的音箱,但在此之前,还得先为 Music Assistant 选择一个播放器,点击右下角扬声器图标,选中需要测试的播放器,接着就可以播放了。

问题

经测试,HomePod Mini 可以正常播放,但美中不足的是经由 Music Assistant 播放时无法在其顶部的触控区进行音量操作(前文协议对比图中有提及),尝试用 Siri 请求下一首也不成功 (Siri 表示当前未在播放)。

但另一边的 XiaoMi Sound 就直接不出声了,明明用手机的 Airplay 就很正常的。但考虑到 HomePod Mini 那边也存在一些问题,XiaoMi Sound 这种搞不好都没有授权的 Airplay 会这样也就不是很奇怪了。

不能控制音量并没有对我造成很大的困扰,因为这俩音箱本身就只是放在咖啡间和浴室起到一个背景音的作用,只要最大音量控制在不扰民的范围就 OK。但 XiaoMi Sound 不能播放这一点就只好另寻方法了。

小米本身是有一个叫小米妙播的音频传输协议的,虽然它极有可能是基于 DLNA 实现的,但我无法通过在 DLNA 扫描到这个设备。Google Cast 自然也不会有,Sonos 那些私有协议就更不用多想了。最后便只好把目光放到了 Home Assistant 上了。

XiaoMi Sound 在通过 XiaoMi Miot Auto 这个集成接入 HA 中生成一个可用于播放暂停、调节音量和静音的 media_player 实体。即便无法由此认定它可以用来播放音乐,但作为仅剩的可能性也算值得一试了。

进入 Settings 页面后 Add Player Provider,选择 Home Assistant MediaPlayers,在常规设置的 Player entities 下拉列表中选中 XiaoMi Miot Auto 所生成的那个 media_player 实体。接着就能像之前那样测试新加入的播放器是否能正常播放了。

幸运的是,尽管以 Home Assistant 的方式接入到 Music Assistant 的播放器在操控和状态显示上都不太令人满意,但是最终还是正常让声音在它上面响起了 。

Home Assistant

现在已经可以通过 Music Assistant 的媒体库调用两个音箱播放音乐了,但这样其实并没有比用手机直接 Airplay 来的方便。并且在家里的话,手机也不一定总是随身的,那么接下来要做的事情就显而易见了。

想要在 Home Assistant 里控制 Music Assistant 还需要安装对应的集成 Home Assistant Integration 才能看到 Music Assistant 中的播放器。其中也会有由 Home Assistant 提供给 Music Assistant 后再出口转内销回来的同名播放器,在使用的时候需要好好区分 entity_id 以免误用或是套娃。

无线开关

无线开关是个好东西,哪里有需要就往哪里一贴。在开关上追求复杂的需求自然是不太现实的,因此只要让它被按下时能播放最常听的歌单即可。

image.png

顺便为播放器打开 shuffle,防止每次都从同一首歌开始播放。

image.png

TTS

Music Assistant 在通过在线音乐服务播放时,从启动到出声会有不小的延迟,这对于在使用无线开关,尤其是在使用双击作为触发动作的时候,由于无法直接观测到指令执行情况,这份延迟会带来一定程度的怀疑感。比较合理的办法是让它在播放前的闲置时间里先放一段通知来增加确认感。

这里可以直接使用 Music Assistant 提供的 Play Announcement Action 服务,但它只能播放事先准备好的音频文件,若要像语音助手那样把要播放的内容一起说出来,就需要借助 TTS(Text to Speech)服务了。

Home Assistant 自己有一个付费的 Home Assistant Cloud 服务可以提供 TTS,但仅仅为了 TTS 的话我们有很多免费好用的第三方集成可以选择,比如 Microsoft Edge TTS

Microsoft Edge TTS 可直接在 HACS 找到,安装完毕后按照文档提供的范例在 configuration.yaml 中添加配置信息后重启 Home Assistant 就可以调用 tts.edge_tts_say 这个服务了。

tts:
  - platform: edge_tts
    service_name: edge_tts_say
    language: zh-CN-XiaoxiaoNeural
    volume: +10%

image.png

快捷指令

解决了从无到有的基础需求后,偶尔也会想听点别的换换口味,那么只需要像前面那样多制作几份不同音源的播放脚本就好了。

但将这些并非常用的指令绑定在实体开关上当秘籍用就显得有点地狱了,不如用 Shortcuts 之类的工具封装成可以一键启动的快捷指令,这样无论是放到那些带屏终端还是直接操作手机都会比较方便。

用 iOS 可以很方便地直接在自带的快捷指令中调用 Home Assistant 的各种服务,但是安卓和其他桌面设备需要考虑的就多了 —— 那倒也不是 —— 直接使用 Home Assistant 的 REST API 就好了。

curl \
  -H "Authorization: Bearer TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"entity_id": "script.ma_coffeeroom_jazz"}' \
  http://homeassistant.local:8123/api/services/script/turn_on

使用前需要先创建一个长期访问令牌来替换掉请求头中用于认证的 TOKEN,只需要在 Home Assistant 应用界面中点击自己的头像,进入安全页面拉到最下方就能找到。

image.png

iOS 依然只需要用自带的快捷指令就可以很方便的发送 http 请求,如果是安卓的话使用 Http-Shortcuts 也很不错。

如果能在 iOS 的快捷指令中获取到播放指定歌单的命令的话,直接用快捷指令在手机上播放并启动 Airplay 会更好,只是 Spotify 只能通过 Siri 根据习惯生成指令,并不太可控。

到这里,以家庭自动化为核心的音乐播放系统的基础已经打造的差不多了,想要进一步拓宽规模话,大概就是为全屋音乐增设音箱,或是音频控制交互方面的改进了。但这些就需要慢慢根据自己的日常生活习惯和体验情况来按需定制了。