Node-RED と Sonos で学校チャイムシステムを作ってみた。

# はじめに
最近、仕事はリモートワークが主流になり、子供は学校が休校で在宅になり、平日と休日のメリハリをつけるのが難しいなぁと感じています。平日はできるだけ規則正しく行動するために学校チャイムシステムを作ってみました。

# 必要なもの
- <A HREF="https://www.sonos.com/ja-jp/home">Sonos</A>  
  - Sonos One、Sonos Beam など
- <A HREF="https://sakazuki.github.io/node-red-desktop/">Node-RED Desktop</A>  
  - node-red-contrib-sonos-plus モジュールを追加でインストールします。
- MacBook  
  - Node-RED Desktop を動かす PC。今回は MacBook Pro を使用しました。
- 音源 (学校チャイム)
  - フリー素材サイト <A HREF="https://otologic.jp/">OtoLogic（オトロジック）</A>を利用させていただきました
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/004978fc-3666-f0b5-0719-945c0d30a14c.png" width=50%">

# 仕組み
Sonos は Wi-Fi (有線接続も可) でネットワークに接続されたスピーカーシステムで、<A HREF="https://musicpartners.sonos.com/?q=docs">Sonos Labs</A> で API が公開されていますので、好きな音楽を流している時でも Notification を使用して途中で割り込み再生することが可能です。
処理の流れは以下のようになります。

1. Node-RED から Sonos へ Play_Notification コマンドで 指定した mp3 ファイル (学校チャイム) の再生を指示します。
2. Sonos は指定された mp3 ファイルを Node-RED から取得します。Node-RED は mp3 ファイルのデータを Sonos へ渡します。
3. Sonos は mp3 ファイルを再生します。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/724cda2f-75ae-12d7-c511-2fffcb6aa036.png" width="75%">

# Node-REDフロー
フローの全体図は以下のようになります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/9ccce4a5-e638-5a1b-614f-52d48f048d69.png" width="75%">

## Node-RED Desktop の起動オプションを指定する
<A HREF="https://discourse.nodered.org/t/announce-node-red-desktop-v1-0-0-released/18642">セキュリティ上の理由</A>で、外部 (今回は Sonos) からの HTTP GET リクエストを受け付けない設定で起動するので、環境変数 NRD_LISTEN_IP を設定して起動する必要があります。

```bash
$ NRD_LISTEN_IP=0.0.0.0 /Applications/Node-RED-Desktop.app/Contents/MacOS/Node-RED-Desktop 
```

## Node-RED Desktop の待ち受けポート番号を変更する (必要に応じて)
メニュー → Node-RED-Desktop → Settings で待ち受けポート番号を変更できます。
今回はデフォルトの 1880 から 1881 へ変更しています。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/6ad50817-a62d-07cf-9262-eb3cd202dce6.png" width="75%">

## mp3 ファイル (学校チャイム) を配置する
今回は MacBook Pro を使用したので、/var/tmp ディレクトリに mp3 ファイルを配置しました。
http://192.168.3.12:1881/School_Bell01.mp3 へアクセスすると /var/tmp ディレクトリに配置した mp3 ファイル (School_Bell01.mp3) を渡します。
IPアドレス (192.168.3.12) は MacBook Pro の IP アドレスです。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/a2275094-a4f2-0271-3377-d41f551c0364.png" width="75%">

## 学校チャイム を鳴らす時刻を決める
Trigger ノードを使用して指定した時刻に学校チャイムを鳴らします。複数の Trigger ノードを作成すれば複数回、学校チャイムを鳴らすことができます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/05dccb74-1164-0419-049d-1befee2abdbf.png" width="75%">
![スクリーンショット 2020-04-03 12.03.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/e3d2c401-77e4-d644-7b86-1b68847259f6.png)

## 再生する mp3 ファイルと音量を指定する
Change ノードを使用して msg.topic に再生する mp3 ファイル (mp3 ファイルを取得する URL) を、msg.volume に音量を指定します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/d147018a-c75d-c94a-0f11-b8e9463b5192.png" width="75%">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/024275a7-6aed-47cb-3167-08238ca338c5.png" width="75%">

## Sonos の IP アドレスを設定する
追加した node-red-contrib-sonos-plus モジュールの Ctrl Player ノードを使用して Sonos の IP アドレスを設定します。Serial Number は入力しなくても動作に問題ありません。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/0e94a05b-feb7-78c4-544d-a30ea2b2f84c.png" width="75%">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/b16d4962-1e66-29ab-7f99-144aa6646830.png" width="75%">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/72479/7d9ddcf6-ad3d-ff69-b503-b2ad483d7de4.png" width="75%">

フローのコードは以下です。
```json
[{"id":"d1da1e30.2e21a","type":"tab","label":"Flow 1","disabled":false,"info":""},{"id":"3e155b85.4f10c4","type":"http in","z":"d1da1e30.2e21a","name":"","url":"/School_Bell01.mp3","method":"get","upload":false,"swaggerDoc":"","x":150,"y":100,"wires":[["afd3a6c6.7343b8"]]},{"id":"afd3a6c6.7343b8","type":"file in","z":"d1da1e30.2e21a","name":"","filename":"/var/tmp/School_Bell01.mp3","format":"","x":420,"y":100,"wires":[["2a2dfb78.ac6ff4"]]},{"id":"2a2dfb78.ac6ff4","type":"http response","z":"d1da1e30.2e21a","name":"","statusCode":"","headers":{"content-type":"audio/mpeg"},"x":630,"y":100,"wires":[]},{"id":"24b7dbd8.0c8c94","type":"comment","z":"d1da1e30.2e21a","name":"http://192.168.3.12:1881/School_Bell01.mp3","info":"play tts notification","x":210,"y":60,"wires":[]},{"id":"a4229c46.10f63","type":"inject","z":"d1da1e30.2e21a","name":"trigger","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"05 12 * * *","once":false,"onceDelay":0.1,"x":120,"y":200,"wires":[["f82094b.9620068"]]},{"id":"f82094b.9620068","type":"change","z":"d1da1e30.2e21a","name":"play_notification - local file - with volume","rules":[{"t":"set","p":"payload","pt":"msg","to":"play_notification","tot":"str"},{"t":"set","p":"topic","pt":"msg","to":"http://192.168.3.12:1881/School_Bell01.mp3","tot":"str"},{"t":"set","p":"volume","pt":"msg","to":"10","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":376,"y":219,"wires":[["ac95f06c.66f11"]]},{"id":"ac95f06c.66f11","type":"sonos-control-player","z":"d1da1e30.2e21a","confignode":"3391a916.11aae6","name":"","x":657,"y":237,"wires":[["1e7c68a.2b9ae97"]]},{"id":"1e7c68a.2b9ae97","type":"debug","z":"d1da1e30.2e21a","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":812,"y":237,"wires":[]},{"id":"5dcb7993.8a5fa8","type":"comment","z":"d1da1e30.2e21a","name":"Sonos: 192.168.3.35","info":"play tts notification","x":670,"y":200,"wires":[]},{"id":"1b2ed128.10d06f","type":"comment","z":"d1da1e30.2e21a","name":"12:05","info":"play tts notification","x":90,"y":160,"wires":[]},{"id":"3391a916.11aae6","type":"sonos-config","z":"","name":"sonos","serialnum":"","ipaddress":"192.168.3.35"}]
```