Spotify物理リモコンを作ってみた

# はじめに
2022年のIoTLTにて何度かLTさせていただきましたが、アプリやWebのソフトウェアUIではなくコンポのリモコン感覚で物理ボタンをポチポチしてSpotifyをコントロールしたい、という思いからSpotify物理リモコンを作りました。

**[Spotify物理リモコン（ProtoPedia）](https://protopedia.net/prototype/3314)**

https://twitter.com/miso_develop/status/1530481301672734721



# できること
赤外線リモコン（NEC、AEHAフォーマットのものならなんでもOK）でSpotifyを操作できます。操作できることとしては、

* 再生/停止
* 曲送り
* リピート切替
* シャッフル切替
* 音量調節
* 任意のプレイリスト再生
* 再生機器の変更（Google HomeやAmazon Alexa、スマホアプリやWeb UI等）
* 今聴いているプレイリストをもとにラジオ（関連楽曲プレイリスト）生成

といった感じで結構いろいろできて、それらの操作を好きな赤外線リモコンの好きなボタンに割り当てられます。またSpotify Web APIを使用しているのでスマホ（アプリ）やPC（Web）は不要です。



# システム構成図

![.](https://user-images.githubusercontent.com/22117028/206642159-91bca27f-3e5f-44c2-8ad5-1cd817a56ea5.png)



# 使用しているハードウェア

* 赤外線リモコン
	* NEC、AEHAフォーマットのものならなんでもいいです
	* [100均のリモコン](https://jp.daisonet.com/products/4972822710244?variant=39703788126381)は出力弱めです
	* 私は余ってた日立製照明のリモコンを使ってます

* [M5ATOM Lite](https://www.switch-science.com/products/6262)
	* 赤外線受信機をつなげて赤外線信号をデコードするために使用
	* Raspberry Piとopniz接続されており、デコードされた赤外線情報をリアルタイムに連携
	* 円安で値上がってしまいましたが1,500円で買えるWi-Fi/Bluetooth搭載マイコン

* Raspberry Pi
	* M5ATOM Liteから連携された赤外線デコードデータを受け、対応するSpotifyの操作をSpotify Web APIにて実行
	* 同じく円安で値上がりどころか入手困難に
		* 役割自体は[Raspberry Pi Zero W](https://www.amazon.co.jp/Raspberry-Pi-Zero-WH-%E3%83%98%E3%83%83%E3%83%80%E3%83%BC%E4%BB%98%E3%81%8D/dp/B07BHMRTTY)でも可能
			* 私はホームサーバーでこれ以外でも活用しているRaspberry Pi 3B+で動かしています
	* ここはRaspberry Piではなくクラウド環境でも可

ちなみにRaspberry PiをなくしてM5ATOMからSpotify Web APIを実行してもいいですし、逆にM5ATOMをなくしてRaspberry Piで赤外線信号を受信してもいいです。M5ATOMとRaspberry Piを使っている理由はopnizによりさくっと連携できることと、赤外線の受信部を取り回しやすいM5ATOMにしておくと置き場に困りにくいからです。
（我が家ではSpotify Web APIをたたくRaspberry Piが赤外線信号の届かないサーバールームにあったりします）

:::note info
M5ATOMとRaspberry Piを分ける理由のひとつとして責務の分離もあります。私の設計方針としては、マイコン（M5ATOM）はセンサーデータの取得といった物理レイヤーのみの責務とし、取得したデータをもとに何か処理を行なうのはサーバー側（Raspberry Pi）の責務としています。

理由としては物理レイヤーではコード外の影響によるバグが発生しやすいため、なるべく責務を絞って特定しやすくする意図があります。また開発、デバッグ時もマイコンのコードを絞ることで、変更コードの再書き込みといったどうしても手間や時間のかかるフローも削減できます。
:::



# 技術スタック

## [Spotify Web API](https://developer.spotify.com/documentation/web-api/)
* Web APIなのでどの言語でもいけますが、今回TypeScript（Node.js）を使用
	* 理由としては書き慣れているのとIoTフレームワークのopnizが対応しているからです
* [Spotify Web API Node](https://github.com/thelinmichael/spotify-web-api-node)というラッパーライブラリを使用
* Web API自体はわりかしローレベルなのでAPIを組み合わせて実装する必要がある感じ
	* 上記のライブラリをもとに目的の操作をメソッド化したクラスを実装
* Spotify Developer Consoleでアプリを作成しクライアントID/シークレットを発行して使う
* Web ConsoleでAPIをさくっと試せる
	* 実際に実装する際はOAuth2.0でのアクセストークン、リフレッシュトークンの取得やリフレッシュを実装する必要がある
* APIでの再生制御にはSpotifyのプレミアムプランが必要

## 赤外線受信
* M5ATOM Liteへよくある赤外線受信機を直挿しして使用
	* GND、5V、25ピンに挿しているので足をいい感じに曲げる必要あり
* [Arduino IRremote](https://github.com/Arduino-IRremote/Arduino-IRremote)という赤外線受信の鉄板ライブラリを使用
	* NECフォーマットのみ対応（百均リモコンはこれでいけた）
* 日立製照明リモコンのフォーマット（AEHAフォーマット）が対応してなかったので仕様をもとに実装
	* 仕様を調べると大体このサイトに行き着く
		* [赤外線リモコンの通信フォーマット](http://elm-chan.org/docs/ir_format.html)
			* NECフォーマット、AEHAフォーマット、SONYフォーマットの3つがメジャーなフォーマット
	* あとから調べたらNEC、AEHAフォーマットに加えSONYフォーマットにも対応してる受信ライブラリがあった
		* [katsumin/irDecoder（GitHub）](https://github.com/katsumin/irDecoder)
		* [赤外線リモコンデコーダ（Qiita）](https://qiita.com/katsumin/items/517cd9fbe66e26d72fa7)

## [opniz](https://github.com/miso-develop/opniz)（マイコン制御）
* M5StackといったESP32搭載マイコンをNode.jsから制御できるIoTフレームワーク
	* マイコンとNode.jsを動かしているPCやサーバー同士をWebSocketでつないでリアルタイム通信
	* [マイコン用ライブラリ](https://github.com/miso-develop/opniz-arduino-m5atom)と、[Node.js SDK](https://github.com/miso-develop/opniz-sdk-nodejs)がある
* 今回はM5ATOM LiteとRaspberry Piをopniz連携
	* M5ATOMで赤外線信号を受けたら、Raspberry Piにデコードデータとともにイベント送信
	* Raspberry PiではM5ATOMからのイベントがきたらデコードデータに対応した処理（Spotify Web API）を実行
* マイコンにスケッチを書き込む必要があるけど[opniz CLI](https://github.com/miso-develop/opniz-cli)でさくっとできる



# 作ってみた感想
普通に便利！…なんだけどこれだけのためにSpotifyプレミアムプラン加入は家庭内稟議NGに…（いまフリープランが充実しすぎていてWebから使う分には曲選択や再生時間の制限なかったりするので…）。なのでしばらく使ってなかったけど、最近カムバック的なキャンペーンで無料でプレミアムプラン復帰できたので復活しました。

あと赤外線受信ってもっとポピュラーになってもいいんじゃないかと思いました。ググってみるとなかなか情報がありませんでした。赤外線送信はめちゃくちゃひっかかるのですが…
物理的なボタンUIってやっぱ便利で汎用性は結構あるんじゃないかと思います。それに赤外線リモコンというハードウェア自体が枯れたハードウェアで高品質ですし。

あれだけボタンの押し心地良くて、電池稼働できて、コンパクトで壊れにくいハードが安価で簡単に手に入るので、物理ボタンUIが欲しくなったらぜひ選択肢のひとつに考えてみてはいかがでしょうか。