自作のスマートディスプレイを作成する

普段使っているスマートディスプレイ「Google Nest Hub」ですが、結局のところお気に入り画像と時計表示にしか使っていない。。。
それぐらいのことであれば、自作もできるだろうと思い、CordovaとAndroidを使って、自分カスタムのスマートディスプレイを作成しました。以降、カスタムスマートディスプレイ(CSD)と呼びます。

まずは、簡単に構成を説明した後、その中で利用している要素技術を説明します。
機能としては、まずは以下の3つの機能を付けますが、今後拡張していければと思います。

・時刻表示
・お気に入り画像の背景表示
・音楽のバックグラウンド再生

# システム構成

以下のような構成になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/4ae68ccc-c789-6ca3-4276-a15133eda944.png)

・Androidタブレット
　これが今回作成するCordovaアプリが動作するAndroidタブレットです。スマートディスプレイとして設置するので、大きめがよいかと思います。私の場合は、AndroidタブレットであるAmazon Fire 8インチを使いました。

・BLEスピーカ
　これは、必須ではありません。Androidタブレットで音楽再生しますが、音質が気になるようであれば、外付けでBLE/Bluetoothで接続できるスピーカを用意するのがよいです。また、GoogleのスマートスピーカであるGoogle Nest Miniもスピーカにすることができます。

・ラズパイ
　音楽再生や背景画像のコンテンツファイルを配置し、Node.jsサーバを立ち上げて、AndroidタブレットやESP32と通信します。常時起動させることになります。ラズパイである必要はなく、通常のPCでも問題ありません。

・ESP32
　Androidタブレットのタッチパネルで操作するのでもよいのですが、せっかくなので、赤外線リモコンを使って操作できるようにしました。赤外線を扱うために、赤外線送受信ユニットが必要であり、それを制御するためにESP32を採用しました。私の場合は、M5StickCを使いました。

https://www.switch-science.com/products/6470

・赤外線送受信ユニット
　赤外線の送受信のためのデバイスです。ESP32とはGroveケーブルで接続します。

https://www.switch-science.com/products/5699

・赤外線リモコン
　赤外線を送信するためのリモコンです。よく一般に「国内外メーカ〇〇社対応のテレビリモコン」などの名前で売られているものです。赤外線コードは何でもよいので、選ぶとしたら、ボタンが大きめで机に置いたままでも使えるものがよいかと思います。

https://www.amazon.co.jp/gp/product/B015DVZH3U/ref=ppx_yo_dt_b_asin_title_o03_s01?ie=UTF8&psc=1

# 画面構成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/261826/fc57cc20-adf5-41f6-7814-67cdc1e4e9c8.png)

通常は、背景画像にお気に入りの画像が表示され、定期的に更新されます。また、時刻と日付が左下に表示されます。
Androidには照度センサがついていますので、照度を定期的に計測し、周りが暗くなった時には、背景画像の表示をやめて黒い背景にし、時刻と日付を画面の真ん中に表示します。
バックグラウンドで音楽を再生するようにしますので、画面タップまたは赤外線リモコンからの赤外線送信で、再生する音楽ファイルの選択時のための画面が表示されるようにします。

# 利用した技術

・Cordovaを採用
・フロントエンドとして、Vue、Vuex、Bootstrapを採用
・常時表示
・最大画面表示
・照度計測
・UDP送受信
・アプリ固定起動
・音量操作
・音楽再生
・赤外線送受信

## Cordovaを採用

CSDのアプリとして、ブラウザを使う手もありましたが、後述するように、リジュームさせず常時表示させたり、アプリ固定起動させたり、と考えると、ブラウザでは実現できず、ネイティブアプリが適していました。また、Android Studioを使って、完全ネイティブアプリとして作成するものありますが、Cordovaであれば、表現力豊かなHTMLやJavascriptで手軽に実装できました。

参考
[Cordovaアプリ開発の備忘録](https://qiita.com/poruruba/items/f03b1691fd0f113735b3)

## 常時表示

Androidは、何もしないとディスプレイがOffとなってしまいます。便利な機能ではあるのですが、スマートディスプレイとして常時表示させたい場合には対策が必要です。
そのためのCordovaプラグインがありますので、利用させていただきました。

https://github.com/Viras-/cordova-plugin-powermanagement

``` js
      // 画面常時On
      window.powermanagement.acquire();
```

上記を呼ぶだけです。。。

## 最大画面表示

ブラウザの場合は、上下にアドレスバーなどが表示され、スマートディスプレイとしては少々邪魔です。
Cordovaアプリであれば、特に何も設定しなくても、ディスプレイ全面で表示してくれます。

## 照度計測

Androidには、加速度センサなど様々なセンサがついていますので、使わない手はないです。今回はその中で照度センサを使います。android.sensor.lightと呼ばれます。
照度センサを使うために、Cordovaプラグインを作成しました。

[Cordovaアプリ開発の備忘録(プラグイン編)](https://qiita.com/poruruba/items/a454f1b90c5d8b0cb2f8)

``` js
      // 照度取得開始
      const light_type = "android.sensor.light";
      samplesensor.addDevice(light_type);

      // 定期的に照度を取得し、背景表示変更
      setInterval(async () =>{
        const values = await samplesensor.getValue(light_type);
        this.background_change_dark(values[0] < BRIGHTNESS_THRESHOLD);
      }, BRIGHTNESS_UPDATE_INTERVAL);
```

## UDP送受信

Node.jsサーバとPullとPushの双方向通信をしたく、PullはHTTP Post(Json)を利用しますが、Pushにはサーバとして立ち上げる必要があり、お手軽にUDP受信を利用しました。
こちらも、Cordovaプラグインを作成しました。

[Cordovaアプリ開発の備忘録(プラグイン編)](https://qiita.com/poruruba/items/a454f1b90c5d8b0cb2f8)

こんな感じで使います。

```js
      // UDPパケット受信開始
      sampleudp.initialize(UDP_LOCAL_PORT);
      sampleudp.registerReceiveListener(this.onUdpReceived);
      console.log("SampleUdp initialized");

      // ・・・

    onUdpReceived: async function(data){
      console.log("udp received: ", data);
      // ・・・
   }
```


## アプリ固定起動

最近のAndroidでは、たいていアプリの固定起動ができます。今回作成したCordovaアプリを固定起動に指定すると、戻るボタンを押してもホーム画面に戻ることはなく、常にCordovaアプリが起動した状態になるので、非常に都合がよいです。
AndoidOSの標準機能なので、特に開発は不要です。

https://support.google.com/android/answer/9455138?hl=ja

## 音量操作

AndroidOSのメディア音量をCordovaアプリから操作します。そのためのプラグインを利用させていただきました。

https://github.com/jlorente/cordova-plugin-volume-control

こんな感じで使います。

```js
    // 音量を上げる
    volume_up: function(){
      console.log("volume up");
      cordova.plugins.VolumeControl.getVolume(volume =>{
        volume = parseFloat(volume);
        if( volume >= 1.0 - VOLUME_STEP )
          volume = 1.0;
        else
          volume += VOLUME_STEP;
        cordova.plugins.VolumeControl.setVolume(volume);
        this.volume = volume;
      });
    },

    // 音量を下げる
    volume_down: function(){
      console.log("volume down");
      cordova.plugins.VolumeControl.getVolume(volume =>{
        volume = parseFloat(volume);
        if( volume <= VOLUME_STEP )
          volume = 0.0;
        else
          volume -= VOLUME_STEP;
        cordova.plugins.VolumeControl.setVolume(volume);
        this.volume = volume;
      });
```

## 音楽再生

Cordovaではお決まりの機能ですね。以下のプラグインを利用します。

https://cordova.apache.org/docs/en/11.x/reference/cordova-plugin-media/index.html

こんな感じで使います。

```js
        this.media = new Media(this.play_item, () =>{
          // 再生完了
        }, (err) =>{
          // エラー発生
        });
        this.media.play();
```

## 赤外線送受信

赤外線の送受信には、ESP32に助けを借ります。
Node.jsサーバとUDPで双方向通信できるようにし、ESP32に取り付けた赤外線送受信ユニットで赤外線信号を検出すると、Node.jsサーバにUDPパケットで知らせます。また、赤外線信号を送信したい場合には、Node.jsサーバからESP32にUDPパケットを送信することで知らせます。

# 利用しているCordovaプラグイン一覧

・cordova-plugin-device
・cordova-plugin-media
・cordova-plugin-networkinterface
・cordova-plugin-powermanagement
・cordova-plugin-samplesensor(自作)
・cordova-plugin-sampleudp(自作)
・cordova-plugin-volume-control


# 終わりに

現在、このカスタムスマートディスプレイ(CSD)の紹介資料やカスタム方法を記述した書籍を作成しました。

「AndroidとCordovaで自分カスタムスマートディスプレイ」
https://poruruba.booth.pm/items/4330100

とりあえず、ソースコード一式は以下のGitHubに上げておきます。

https://github.com/poruruba/CustomSmartDisplay


以上