Unityからobnizを操作してみる


#はじめに
初投稿です。
前からArduinoやRaspberry Piなどを使って、OculusRiftなどのVR HMD用アプリと連動させて使える簡単なVR向けハードウェアを作っていたのですが
なかなか、私自身ががっつりメカエンジニアなのでUnityアプリとハードの連携などの環境構築から既にギブアップギブ気味で、VR HMDもOculusQuestシリーズをはじめとした、PCレスのスタンドアロン型が主流になり、より厳しい状況に。もっと開発しやすいボードが無いかとかと探してしていたところ、
ファームウェアレスをうたっている**obniz**が相性が良さそうなので試行錯誤中。
実質マイコンボード側のファームウェア開発が不要となったので、開発の手間が省けて、ハードとアプリソフトの開発だけに打ち込めるのは凄い魅力に感じてます。

#目的
obniz boardのディスプレイコントロールを例に
Unityアプリ（for Oculus Quest2）にて、websocket APIを介したobniz board制御と
Webhook連携によるアプリ起動を使ったobniz board制御
の2種類のobniz board制御手段を整理
単純にUnityとobnizを繋げてるだけなのでVRでなくとも操作可
後述しますが、Websocket APIによる制御は不完全なので注意。
※各ソフト・ファームウェアVer
Unity:2020.3.0f1
obniz OS:obnizb1 3.4.4

#Websocket API制御編
今回やってることはこんな感じ
![システム図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950682/d93bf0bf-0c3c-887b-7adb-a568ea32c87a.png)


obnizのwebsocket APIの導入部分については、以下参考にしました。
そもそもwebscoketって何？っていう人向け（私も導入にあたってめっちゃ参考になった）記事1：https://qiita.com/hmaruyama/items/eee079f035f864638e13

UnityのWebsocketの使用方法、以下参考にしました↓
**【今回必須作業】**記事2：https://qiita.com/oishihiroaki/items/bb2977c72052f5dd5bd9
今回の作業自体は、こちらのwebasocket-sharp(手順1~3でライブラリを読み込む)を行い、4-①のサンプルコードの接続先アドレスを変えるのと、obniz boardディスプレイ操作用のJSON形式の送信データを追加します。

UnityでJSONデータの送信するのに参考にしました。記事3：https://qiita.com/MonoShobel/items/28b99e1753b92ffcdca2
Unityはobniz.jsと違ってC#言語ですので、JSONデータの送信も若干異なります。そこでこちらの記事参考にさせてもらいました。
obniz JSONフォーマットはここを参考：https://obniz.com/ja/doc/reference/websocket/

websokcet通信部分のコードは以下です。

```c#:webscoket.cs
using UnityEngine;
using System.Collections;
using WebSocketSharp;
using  System.Security.Authentication;

public class WebSocketClient : MonoBehaviour
{

 
    private int count = 0; // click counter
    private WebSocket ws;

    void Start()
    {
        this.ws = new WebSocket("ws://*ws.obniz.io/obniz/自分のobnizの番号/ws/1"); //アクセス先をwebsocket APIエンドポイントに指定
                                                                                   //*wsの箇所については、"ws://obniz.io/obniz/自分のobnizの番号/ws/1”
                                                                                   //で送信後にRedirectで帰ってきた値へ変更。アクセストークン有の場合は最後に挿入
        
        this.ws.OnOpen += (sender, e) =>
        {
            Debug.Log("[WS] Open");
        };



        this.ws.OnMessage += (sender, e) =>
        {
            Debug.Log("[WS]Receive message: " + e.Data);//ハード側からメッセージを受け取った場合にLogに記載
        };
        
        

        this.ws.OnError += (sender, e) =>
        {
            Debug.Log("[WS]Error: " + e.Message);//接続失敗した際にエラーをLogに記載
        };
    
        this.ws.Connect();//アクセス先へwebsocket接続

        this.ws.Send("[{\"display\":{\"clear\":true}},{\"display\":{\"text\":\"Connect\"}}]");//接続されたことをobnizディスプレイに表示

    }

    void Update()
    {
        if (OVRInput.GetDown(OVRInput.RawButton.RIndexTrigger))
        {
            Debug.Log("clicked!");
            count++;
          this. ws.Send("[{\"display\":{\"clear\":true}},{\"display\":{\"text\":\"Hello.world\"}}]");//Oculus questのトリガーボタン押すとディスプレイにメッセージ表示

        }
    }
}
```

アクセス先の部分に注記している通り、Redirectで出てくるエンドポイント指定処理は出来ておらず、一日一回手動でコード直して対応してます。。。
目的自体は出来てるのですが、もう少しいけてる感じにしたいなと。そこは修正したら編集・追記します。
（Unity側でID指定やアクセストークン指定とかもしたいけど、そんときは別記事で。）
その他、注意点として
・今のままだとwss://で送れないので、エンドポイントをws://にしておく必要がある。(いい方法ないかな～)
・JSON形式でのデータ送受信なので、基本的には日本語が使えない。そもそも認識されないか、文字化けする。はず（多分やり方はあるかな？）

#Webhookトリガーのアプリ起動による制御編
こっちはこんなイメージ（※についてはWeb上にデータ送信自体とかは可能だけど、指示側デバイスと直接データやり取りは出来ませんよ的な意味です）
![システム図2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/950682/3c6e2db7-7d38-8b14-7092-b8caf661b3cd.png)

ここで参考にしたのは
こちらのobnizガイドを基に、あらかじめobniz.js作ってWebhookトリガーにして登録したのみ:https://obniz.com/ja/doc/reference/cloud/serverless-event/
以上。

obnizサーバー側のコードはほぼサンプルコードなので省略して
Unity側のwebhookエンドポイントへの接続のコードがこちら

```c#:Webohook
using UnityEngine;
using System.Collections;
using  System.Security.Authentication;
using UnityEngine.Networking;

public class Webhook : MonoBehaviour
{
    private WWW www;
    private bool isDone;

    // Use this for initialization
    void Update()
    {
        if (OVRInput.GetDown(OVRInput.RawButton.RIndexTrigger))//Oculus Questのトリガーボタンを押すとURLへ接続開始
        {
 
        var url ="指定したイベントのwebhook urlを貼り付け";//接続先URLの指定

        Request(url);
        }
    }

      public void Request(string url)
    {
        www = new WWW(url);
        isDone = false;
    }
}
```
注意点としては
・複数のイベントで複数の動作をさせたいなら、開いたイベントを閉じる必要がある。（分かってないだけで、やり方分かればまとめたい。）
・1イベントごとに接続～動作になるのでwebsocketAPIと比べて応答性が若干遅い（JSON形式でのやり取りがしない分、こっちのほうが開発がしやすい気はする。）

#まとめ
簡単な動作で粗削りではあるけど、マイコンボードとVR HMDを組合せた実装環境が出来たので、アイデア抽出・ハード開発をしっかりして
実装はこれを基本的に応用すれば、作品の試作は十分に出来るのじゃないかと。
今年はこちらを基盤とした基盤としたハードを開発しつつ、完成度上げていきたいです。
以下に動作の様子を載せております。
<iframe width="560" height="315" src="https://www.youtube.com/embed/lLsuNXxgBgc" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>