LoginSignup
0
0

More than 3 years have passed since last update.

Web of Things(WoT)を使ってWebブラウザ上で動作するIoTサンプルを作ってみる

Posted at

はじめに

Web of Things(WoT)は、Web技術を使ってInternet of Things(IoT)を実現するための、W3Cが策定する標準技術です。

このWoTを利用してセンサーなどを接続したデバイス上で稼働するThingと、Thingと接続してデータの確認や操作を行うClientを各々ブラウザ上で実現してみます。今回実現するThingはcountというプロパティを持つダミーですが、Webブラウザ上でもGPSの値や向きなどを取れるため、そのようなデータを取得できるように実装しても良いかもしれません。
WoTではThingのインターフェースをThingDescriptionで定義します。インターフェースには以下の3種類があります。

  • プロパティ: Thingが持つセンサーなどの情報にClientからアクセスできるようにします。プロパティには読み取り専用/読み書き可能や、変化のあった際に通知するかどうかの属性があります。
  • アクション: Thingが持つ機能をClientから呼び出せるようにします。
  • イベント: Thingで発生した事象をClientに通知します。

また、ThingとClient間の通信はBindingと呼ぶ標準化されたモジュールが担います。
今回はFirestoreを利用したBindingのブラウザ版を利用します。このBindingの詳細についてはWeb of Things(WoT)のFirestore Bindingの紹介をご参照ください。

またここで紹介するサンプルは以下で公開していますのでソースコードの全体はこちらで確認してください。

実装方法の概要

Thing

WoTを利用した場合、Thingの実装手順は以下となります。

  1. Thingが持つインターフェースをThingDescriptionとして定義する
  2. ThingDescriptionで定義したインターフェースの実装を行う

Client

WoTを利用した場合、Thingに接続してThingの出す値を参照したりThingを操作するClientを実装する手順は以下となります。

  1. ThingDescriptionをフェッチする(Thingを操作するためのThingオブジェクトが生成される)
  2. Thingオブジェクトを通してThingの操作を行う

実装方法

ThingDescriptionのインターフェースの種類毎に実装の例を示します。

ライブラリの読み込み

Thing、Client共に以下のスクリプトを読み込みます。

<script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@node-wot/browser-bundle@latest/dist/wot-bundle.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@hidetak/binding-wotfirestore-browser-bundle@latest/dist/binding-wotfirestore-bundle.min.js"></script>

画面の操作にjqueryを利用していますので最初の行で読み込んでいます。

Firestoreとの接続設定の読み込み

Firestoreを利用したBindingを利用するために、Firebaseを設定する必要があります。設定の仕方は以下を参照ください。

また、Firestoreと接続するための設定を読み込む必要があります。今回、設定はJavaScriptのファイルで定義するようにしました。内容を以下に示します。

const firestoreConfig = {
    "hostName": "sample-browser-host",
    "firebaseConfig": {
        "apiKey": "<API Key of Firebase>",
        "projectId": "<Project Id of Firebase>",
        "authDomain": "<Auth Domain of Firebase(Usually it will be <projectId>.firebaseapp.com>"
    },
    "user": {
        "email": "<email address registered in Firebase>",
        "password": "<password corresponding to the email address above>"
    }
}

Firebaseに設定した内容に応じて適宜設定を記載してください。設定したファイルは通常のJavaScriptの読み込みと同様に以下のように読み込みます。

<script src="firestore-config.js"></script>

注意: 今回はサンプルであるためJavaScriptファイルに設定を記載して読み込ませていますが、この方法ではWebブラウザを利用するユーザーが簡単にFirestoreに接続するための認証情報(具体的にはuserのemailとpassword)を見ることができます。本来、この認証情報が見えてはいけないため、FirebaseのAuthentication機能を利用するなどしてユーザーにFirebaseにログインしてもらった上で利用できるようにすべきです。

プロパティ

Thingのプロパティ実装

countというプロパティを定義し、ユーザーがその値を自由に変更できるようにします。
また、そのcountの値が変更されると、Clientに値が通知されるようにします。

1. Thingが持つインターフェースをThingDescriptionとして定義する

countプロパティのThingDescriptionの定義を以下に示します。

properties: {
    count: {
        type: "integer",
        observable: true,  // 変更されたときにClientに通知されるようにします
        readOnly: false  // countを変更できるようにします
    }
},

2. ThingDescriptionで定義したインターフェースの実装を行う

countプロパティの実装を以下に示します。

<div>count: <span id="countArea"><input id="countInput" type="text" value=""/><button id="countUpdate">update</button></span></div>
・・・
thing.writeProperty("count", 100)  // countプロパティに100を書き込みます
$("#countUpdate").click(()=>{
    let v = Number($("#countInput").val())
    thing.writeProperty("count", v)  // updateボタンを押すと入力フォームに入力された値をcountプロパティに書き込みます
    thing.emitEvent('update', v)  // イベントを発行します(あとで説明します)
})

Clientのプロパティ実装

1. ThingDescriptionをフェッチする

FirestoreのBindingでは、ThingのThingDescriptionにはwotfirestore://ではじまるURLでアクセスできます。以下のコードでThingDescriptionのURLをフェッチし、ClientからThingにアクセスするためのthingオブジェクトを作成します。

wotHelper.fetch("wotfirestore://sample-browser-host/MyCounter").then(async (td) => {
    servient.start().then((WoT) => {
        WoT.consume(td).then((thing) => {
・・・
        }
    }
}

2. Thingオブジェクトを通してThingの操作を行う

Thingのcountの値が変化したときにClientで検知できるようにします。また、初期値を画面に表示するためにThingの値を取得します。

<div>count: <span id="count">no data</span></div>
・・・
thing.observeProperty("count", (v) => {
    $("#count").html(v)  // Thing側でcountの値が更新されたときにこのコールバック関数が呼ばれます
})
thing.readProperty("count").then((v) => {
    $("#count").html(v)  // Thingからcountの値を読み込み、画面に表示します
})

アクション

Thingのアクション実装

resetアクションを定義します。
resetアクションを実行すると、countプロパティを0に変更します。

1. Thingが持つインターフェースをThingDescriptionとして定義する

resetアクションのThingDescriptionの定義を以下に示します。

actions: {
    reset: {
        description: 'Resetting counter value',
    }
},

2. ThingDescriptionで定義したインターフェースの実装を行う

resetアクションの実装を以下に示します。

thing.setActionHandler('reset', async () => {  // resetアクションが呼び出されるとこのコールバックが実行される
    await thing.writeProperty('count', 0)  // countプロパティの値を0にする
    await thing.emitEvent('update', 0)  // イベントを発行します(あとで説明します)
})

Clientのアクション実装

1. ThingDescriptionをフェッチする

プロパティでの説明と同様です。

2. Thingオブジェクトを通してThingの操作を行う

Clientからresetアクションを呼び出す例を以下に示します。

<div><button id="resetButton">reset</button></div>
・・・
$("#resetButton").click(()=>{
    thing.invokeAction("reset")
})

resetボタンを画面に配置し、ボタンをクリックするとresetアクションを呼び出します。

イベント

Thingのイベント実装

今回は、countプロパティが変化したことをイベントとして通知する。

1. Thingが持つインターフェースをThingDescriptionとして定義する

イベントの通知と共にcountの値を通知することにします。

events: {
    update: {
        description: 'Update count event',
        type: 'integer'  // countの値を通知するためintegerとします
    }
}

2. ThingDescriptionで定義したインターフェースの実装を行う

イベントの通知は以下のように実装します。

thing.emitEvent('update', v)  // vはcountプロパティの値です

プロパティとアクションの実装で示したようにcountプロパティに

Clientのイベント実装

1. ThingDescriptionをフェッチする

プロパティでの説明と同様です。

2. Thingオブジェクトを通してThingの操作を行う

Thingで発生したイベントの通知を受け取るように実装します。

<div>update: <span id="update"></span></div>
・・・
thing.subscribeEvent("update", (v) => {
    $("#update").html(v)  // イベントとして通知されるcountプロパティの値を画面に表示します
    setTimeout(() => {  // 3秒後に上記の値を消去します
        $("#update").html("")
    }, 3000)
})

実行

上記で説明した実装の全体は以下で公開しています。

Thingはthing.html、Clientはclient.htmlに実装しています。実行するには、各HTMLをWebブラウザに読み込むだけです。
thing.html画面でcountプロパティの値を変更すると、client.html画面に表示したcountプロパティの値が自動的に変更した値に更新されます。また、イベントも発行されるため、client.html画面のupdate欄にもcountプロパティの値が表示され、3秒後に消えます。
また、client.html画面にあるresetボタンを押すと、Thingのcountプロパティが0にリセットされます。thing.html、client.htmlの両画面のcountプロパティが0になり、さらにclient.htmlにはイベントも通知されるため、update欄に0が表示され3秒後に消えます。

おわりに

この記事では、WoTのFirestore Bindingを利用したWebブラウザ上で動作するThingとClientの実装方法を説明しました。
具体的には、WoTのThingの構成要素であるプロパティ、アクション、イベントの実装の仕方を示しました。
プロパティ、アクション、イベントのインターフェースはThingDescriptionとしてThing側で定義しておきます。これをClient側でフェッチすることにより、ClientからThingを操作するためのオブジェクトが自動的に作られます。このオブジェクトを操作することでClientからリモートにあるThingを簡単に操作できますので、IoTシステムの開発のときはThingでセンサーデータなどを扱う部分やClientで収集したデータを処理する部分など、作りたいIoTシステム独自の部分の開発に集中できるようになりますし、同じインターフェースを持つThingが複数種類ある場合には、それらを入れ替えたり、またClientを入れ替えることも実装を変更することなく柔軟に実現できます。

また、ここで説明したプロパティ、アクション、イベントの実装の仕方は基本的にBindingの種類に依存しないため、Firestore Binding以外を利用する場合にも使えるはずです。つまり、WoTを利用することで、ThingやClientの実装とBindingの実装は切り離せるため、通信の仕方が変わった場合にもBindingを入れ替えることで対応できます。

WoTによる開発の参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0