M5Stack / M5StickC で Sonos を操作してみた。

# はじめに
こんにちは。野良ハックチーム ざっきー と申します。
「<A HREF="https://qiita.com/kitazaki/items/ccde18e10f49fcbb9437">Sonos を操作するツールを調べてみた。</A>」で紹介している M5Stack / M5StickC から Sonos を操作する実装に関するメモです。
2019 年 11 月 28 日に開催された「<A HREF="https://enebular.connpass.com/event/152742/">enebular developer Meetup</A>」でデモをやる予定だったのですが、Node-RED の sonospollytts ノードをデモするだけで時間切れでした。。(登壇資料は<A HREF="https://www.slideshare.net/kitazaki/20191128-enebular-meetupkitazakiss">こちら</A>。)

# Sonos とは？
米国サンタバーバラ生まれのワイヤレスホームサウンドシステムです。
https://www.sonos.com/ja-jp/home
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/a578480a-17b0-8266-2721-3ea4e7f70c39.jpeg" width="35%">

Wi-Fi (有線接続も可) でネットワークに接続され、自由な組み合わせが可能なスピーカーシステムです。
<img width="50%" alt="スクリーンショット 2019-12-12 15.25.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/8f6f4abb-2389-2481-75e7-ed395753ec00.png">

UPnP 対応で API が公開されていますので、ハックすることが可能です。
<A HREF="https://musicpartners.sonos.com/?q=docs">Sonos Labs</A>
<img width="50%" alt="スクリーンショット 2019-12-12 15.25.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/a9c90cfc-0661-5fb0-a91f-5c4b598e212d.png">

# やりたかったこと
基本的に Sonos App と呼ばれる公式アプリから操作する必要があるのですが、ちょっとした操作で PC (Mac or Windows) や スマホ (iPhone or Android) を取り出すのは少し面倒です。
<img width="50%" alt="スクリーンショット 2019-12-12 15.31.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/b54b676d-09f7-4fdc-3485-0a16c73cdca5.png">

単純な操作は物理デバイスで行いたかったため、Sonos Music API を利用して M5Stack / M5StickC から曲の再生 / 一時停止・再開、巻き戻し、先送りの操作や音量調節 (ボリュームアップ / ダウン) を行います。
また、M5Stack / M5StickC はディスプレイを備えているので、選曲中のジャケ写を表示してもいいですね。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/62d2d4ed-f2f0-7d8f-ee99-493f85c5a8fd.jpeg" width="45%">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/e978c75e-2344-f1d2-3d4a-22a91f4f6071.jpeg" width="45%">

# 実装
少しややこしい状況になっています。
本家 (<A HREF="https://github.com/tmittet/sonos">tmittet</A> さん) の Sonos Arduino ライブラリのメンテナンスが止まっているため、マージされていません。
<A HREF="https://github.com/antonmeyer/sonos">antonmeyer</A> さんが Arduino ライブラリを fork して Sonos ESP8266 ライブラリを公開されています。
<A HREF="https://github.com/joeybab3/sonos">joeybab3</A> さんが ESP8266 ライブラリを fork して Sonos ESP32 ライブラリと M5Stack サンプルコードを公開されています。
ただ、1 点問題があり、本家で修正された不具合 (音量情報の取得不可) が残ったままになっています。
<A HREF="https://github.com/tmittet/sonos/commit/640aa2e2e395a3f7caf9ecc4723e6f299b98c840#diff-87da73c8d6fe82d41d66c46cd3ed53d9">Fix issue #8 - getVolume returns undefined value</A>
<img width="50%" alt="スクリーンショット 2019-12-14 15.21.20 2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/022c34eb-1c78-26b5-7855-d01fa23659e8.png">
<A HREF="https://github.com/cdietze/sonos">cdietze</A> さんは ESP32 ライブラリ を fork して amazon music album を queue に追加する機能を追加されています。(こちらは上記問題が修正されていました。)

## 構成
M5Stack / M5StickC と Sonos の間は UPnP で接続する必要があるため、SSDP → SCPD → SOAP の順で通信を行います。
SSDP: Simple Service Discovery Protocol ・・・UPnP に対応したルーターを探す
SCPD: Service Control Point Definition ・・・ルーターからドキュメントを取得する
SOAP: Simple Object Access Protocol ・・・ルーターにポートマッピングを設定する

M5Stack / M5StickC のボタンを押して Sonos を操作するのに加えて、ウェブサーバー機能が付いていますので、PC または スマホのブラウザから M5Stack / M5StickC へアクセスして Sonos を操作することもできます。
<img width="50%" alt="スクリーンショット 2019-12-14 20.59.50.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/229fc073-d704-e5c4-6f4f-682be6b91553.png">
<img width="50%" alt="webcon.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/55d64287-2eaf-aefb-865c-095b321c84d0.png">

## 導入準備
Arduino IDE を用いて M5Stack / M5StickC へ導入する前提で手順を説明します。

1. <A HREF="https://github.com/tmittet/microxpath">MicroXPath</A> ライブラリをダウンロードして Arduino ライブラリフォルダ (macOS の場合は /Users/[ユーザー名]/Documents/Arduino/libraries) へ追加します。
<img width="75%" alt="スクリーンショット 2019-10-22 23.38.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/7f4f9ccc-9318-79de-5a82-a035ec3c43e8.png">

2. <A HREF="https://github.com/joeybab3/sonos">Sonos ESP32</A> ライブラリをダウンロードして Arduino ライブラリフォルダ (macOS の場合は /Users/[ユーザー名]/Documents/Arduino/libraries) へ追加します。
<img width="75%" alt="スクリーンショット 2019-10-22 23.38.15.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/28a96a9f-f022-b6ec-3e30-28cf317f6520.png">

3. <A HREF="https://github.com/joeybab3/sonos">Sonos ESP32</A> ライブラリの src/SonosUPnP.cpp を修正する。(getVolume を return getVolume に変更する。)
<img width="75%" alt="スクリーンショット 2019-12-14 16.48.39.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/2096228e-1cfe-665c-1d1a-75e7c1d70dd9.png">

# プログラム
Arduino IDE で以下のプログラムを開いてコンパイル→書き込みを行います。

- M5Stack 巻き戻し、先送り、音量表示対応版  
https://github.com/kitazaki/sonos/blob/master/examples/Sonos_Controller_M5Stack
- M5Stack ジャケ写表示対応版 (Amazon Music のみ)  
https://github.com/kitazaki/sonos/blob/master/examples/Sonos_Controller_M5Stack_2  
- M5StickC 対応版  
https://github.com/kitazaki/sonos/tree/master/examples/Sonos_Controller_M5StickC

## ジャケ写表示対応
現在は M5Stack、Amazon Music のみに対応しています。
ジャケ写画像を Sonos システムから取得し、一旦 SD カードに保存してから M5Stack のディスプレイに表示しているためです。
理由は画像ファイルサイズが大きい場合、保存するメモリ領域が足りなくなるためです。
Amazon Music で実装・動作検証を行ったのですが、後から Spotify を追加して試したところジャケ写画像の URL (<upnp:albumArtURI> タグ) の書式が異なることが判明しました。(´•ω•`未実装)

- Amazon Music  
/getaa?s=1&u=x%2Dsonosapi%2Dhls%2Dstatic%3Acatalog%252ftracks%252fB07RYVSH4P%252f%253fplaylistAsin%253dB07V3HV4G8%2526playlistType%253dhawkfirePlaylist%3Fsid%3D201%26amp%3Bflags%3D0%26amp%3Bsn%3D1  
→http://[Sonos の IP アドレス]:1400 へアクセスして GET リクエストする。
- Spotify  
https://i.scdn.co/image/ab67616d0000b27322cc0ac30507cf2208eb08b  
→https://i.scdn.co へアクセスして GET リクエストする。

# まとめ
先日、SONOS Beam を追加購入し、リビングにも良い音がやってきました。
少しずつ増やして自由に組み合わせられるのが本当に素晴らしいと感じました。
Listen Better!
みなさまにも良き音を！
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/164e59af-949a-5c7e-48a2-af7a609ab4c3.jpeg" width="50%">