アプリケーション開発

チュートリアル

開発の流れ

Symphony ダッシュボードの開発は以下の流れで進めていきます。

1. 認証機能の開発
ダッシュボードを利用するユーザーのサインアップおよびサインインの仕組みを開発します。
2. ゲートウェイの登録
ユーザーがダッシュボードにサインインしたら、最初にゲートウェイを登録しなければいけません。ユーザーが所有するゲートウェイを発見し、それを、ダッシュボードにサインインしているユーザーに関連付ける仕組みを開発します。このステップでは、ゲートウェイが認識しているデバイスを Symphony に登録し、各デバイスが提供するサービスも取得します。
3. アクションの実行
ゲートウェイ配下に登録されたデバイスが提供するアクションを実行する仕組みを開発します。

以上の開発項目が Symphony ダッシュボードの必要最小限の機能です。以降、上記の項目を順を追って解説していきます。

認証機能の開発

ダッシュボードを開発するにあたり、少なくとも、サインインページと、サインイン後に表示するページを用意する必要があります。ここでは以下のディレクトリ構成を想定します。

https://example.jp/
    signin.html       // サインインページ
    top.html          // サインイン後に表示するページ
    symphony-sdk/     // Symphony JavaScript SDK フォルダ
      symphony-sdk.js // Symphony JavaScript ライブラリファイル

上記ファイルはすべて本 SDK に同梱されていますので、参考にしてください。

サインインページの作成

サインインページ (signin.html) では、Google アカウントでサインインするためのボタンと、NTT docomo dアカウントでサインインするボタンを用意します。

<button data-dsymphony="signin-btn-google">Googleアカウントでサインイン</button>
<button data-dsymphony="signin-btn-docomo">NTTドコモ dアカウントでサインイン</button>

それぞれの button 要素には、data-symphony 属性に signin-btn-google および signin-btn-docomo をセットしてください。

上記 HTML マークアップより後に、以下の JavaScript コードを記述します。

<!-- Internet Explorer 11 用 JS ライブラリ -->
<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js"></script>
<!-- Symphony JavaScript ライブラリ -->
<script src="symphony-sdk/symphony-sdk.js" data-dsymphony="sdk-js"></script>
<!-- サインインページを初期化 -->
<script>
  dSymphony.initSigninPage({
    clientId  : '9999999999999',                  // ダッシュボードのクライアントID
    signinUrl : 'https://example.jp/signin.html', // サインインページのURL
    topUrl    : 'https://example.jp/top.html'     // サインイン後のページのURL
  });
</script>

上記コードの冒頭で es6-promise.auto.min.js をロードしていますが、これは Internet Exlorer 11 で ECMAScript の Promise をサポートする Polyfill (古いブラウザでも最新の機能を使えるようにするための JavaScript ライブラリの総称) で、本 SDK を動作させるために必要となります。もし Internet Explorer 11 をサポートする必要がなければ、es6-promise.auto.min.js のロードは不要です。

symphony-sdk.js をロードすると、グローバルスコープに変数 dSymphony が生成されます。以降、この dSymphony オブジェクトに実装されたメソッドを使て、ダッシュボードを開発します。

サインインページでは、ページがサインインページとして機能するよう、dSymphony オブジェクトの initSinginPage() を呼び出します。パラメータとして、クライアント ID、サインインページの URL、そして、サインイン後のページの URL を指定します。

以上で、HTML にマークアップしたサインインボタンが自動的に動作するようになります。これらボタンを押すことによって、サインアップ (Symphony に初めてアクセスした場合) およびサインインが自動的に行われます。サインインに失敗すると、パラメータ signinUrl に指定したサインインページの URL にリダイレクトされます。そして、サインインに成功すると、パラメータ topUrl に指定したサインイン後のページの URL にリダイレクトされます。

サインイン後のページの作成

サインイン後のページでは、まずサインイン済みかどうかをチェックしなければいけません。なぜなら、サインインなしに直接サインイン後のページにアクセスがあるかもしれないからです。もしサインインしていなければ、サインインページにリダイレクトするといった処理が必要になります。次の例では、サインインしていれば、ユーザー名を表示し、サインインしていなければ、サインインページにリダイレクトします。

<p>ようこそ「<span id="user-name"></span>」さん</p>
<!-- Internet Explorer 11 用 JS ライブラリ -->
<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js"></script>
<!-- Symphony JavaScript ライブラリ -->
<script src="symphony-sdk/symphony-v1.js" data-dsymphony="sdk-js"></script>
<!-- -->
<script>
  // サインイン済みかをチェック
  dSymphony.isAuthenticated().then(function(user) {
    if (user) {
      // サインイン済みならページ初期化処理を実行
      dSymphony.initMainPage();
      // ユーザー名を表示
      document.getElementById('user-name').textContent = user['userName'];
    } else {
      // サインイン済みでないならサインインページへリダイレクト
      document.location.href = '/signin.html';
    }
  }).catch(function(error) {
    // エラーならサインインページへリダイレクト
    document.location.href = '/signin.html';
  });
</script>

サインイン済みかどうかは、dSymphony.isAuthenticated() メソッドでチェックします。このメソッドは、サインイン済みであれば、該当のユーザー情報を格納したオブジェクトを返します。そうでなければ null を返します。

サインイン済みであれば、dSymphony.initMainPage() メソッドを呼び出して、ページの初期化処理を行います。


サインイン後のページでは、サインアウトのリンクを用意します。Symphony には 2 種類のサインアウトが用意されています。

セッションを維持したままサインアウト
Symphony 内のセッションは維持したまま、該当のクライアントをサインアウトします。もし 2 つ以上のクライアントから同じユーザーでサインインしていた場合、もう一方のクライアントには影響を与えません。
セッションを削除してサインアウト
Symphony 内のセッションを削除してサインアウトします。もし 2 つ以上のクライアントから同じユーザーでサインインしていた場合、もう一方のクライアントもセッションが無くなるため、Symphony にアクセスできなくなります。

HTML 上に以下のリンクを用意するだけでサインアウト機能が実現できます。

<a href="#" data-dsymphony="signout-keep-btn">セッションを維持したままサインアウト</a>
<a href="#" data-dsymphony="signout-revoke-btn">セッションを削除してサインアウト</a>

前述の dSymphony.initMainPage() は、スクリプトを記述せずとも、この HTML マークアップだけでサインアウトを自動的に処理するよう準備を行います。2 種類のサインアウトは必ずしも必要ではありません。必要に応じて一方のみを用意しても構いません。

なお、上記マークアップは、前述のスクリプトより前に記述してください。

ゲートウェイの登録

ゲートウェイの電源を入れる、または、スマートフォンのゲートウェイアプリを起動すると、自動的に Symphony にそのゲートウェイが一時的に登録されます。しかし、そのゲートウェイはどのユーザーにも関連付けられておらず、しばらくすると、Symphony から削除されます。ゲートウェイの電源を入れた、または、スマートフォンのゲートウェイアプリを起動したら、ユーザーと関連付ける処理を実行する必要があります。

ゲートウェイには必ず個体を識別するための UUID が割り当てられています。ダッシュボードでは、その UUID を登録する仕組みが必要となります。この処理には、dSymphony.setupGateway() メソッドを使います。

以下のサンプルでは、ゲートウェイの UUID を入力するテキストボックスと、処理を実行するボタンを HTML 上にマークアップしています。スクリプトでは、ボタンが押されると、dSymphony.setupGateway() メソッドを呼び出し、その結果をブラウザーのコンソールに出力します。

<input type="text" id="gw-uuid" size="40">
<button type="button" onclick="registerGateway()">登録</button>

<script>
  // 登録ボタンが押されたときの処理
  function registerGateway() {
    // ユーザーが入力した UUID を取得
    let gw_uuid = document.getElementById('gw-uuid').value;
    // ゲートウェイの登録を実行
    dSymphony.setupGateway({ uuid: gw_uuid }).then(function (res) {
      // 成功したら結果をコンソールに表示
      console.log(JSON.stringify(res, null, '  '));
    }).catch(function (error) {
      // 失敗したらエラーをコンソールに表示
      console.error(error);
    });
  };
</script>

処理が成功すると、次のような結果が表示されます。

{
  ...
  "deviceList": [
    {
      "deviceName": "REX-WFIREX1",
      "thingId": "th-2D0AB85CB301495FED4821D22D1737C1",
      "actionInfo": {
        "actionId": "ac-08F0886260D516A34403730D4EAAE378",
        "summary": "湿度センサー計測値の取得",
        ...
      },
      ...
    },
    {
      "deviceName": "REX-WFIREX1",
      "thingId": "th-2D0AB85CB301495FED4821D22D1737C1",
      "actionInfo": {
        "actionId": "ac-CAAB6578B6C72A420CDB396B6DDCA899",
        "summary": "湿度センサー計測値の取得",
        ...
      },
      ...
    },
    ...
  ]
}

ご覧の通り、ゲートウェイが認識しているデバイスの情報、そして、そのデバイスが提供するアクション情報が得られます。ここで重要な情報は actionId です。actionId はアクションの識別子ですが、後にアクションを実行する際に必要となります。

アクションの実行

アクション情報が得られたら、そのアクション ID (actionId) を使って、そのアクションを実行することができます。以下のサンプルでは、アクション ID を入力するテキストボックスと、処理を実行するボタンを HTML 上にマークアップしています。スクリプトでは、ボタンが押されると、dSymphony.requestAction() メソッドを呼び出し、その結果をブラウザーのコンソールに出力します。

<input type="text" id="action-id" class="form-control">
<button type="button" onclick="execAction()" class="btn">実行</button>

<script>
  // 実行ボタンが押されたときの処理
  function execAction() {
    // ユーザーが入力したアクション ID を取得
    let id = document.getElementById('action-id').value;
    // アクションを実行
    dSymphony.requestAction({ actionId: id }).then(function (res) {
      // 成功したら結果をコンソールに表示
      console.log(JSON.stringify(res, null, '  '));
    }).catch(function (error) {
      // 失敗したらエラーをコンソールに表示
      console.error(error);
    });
  };
</script>

例えば、サービス ID に ac-CAAB6578B6C72A420CDB396B6DDCA899 (この例では湿度センサー計測値の取得) を入力して実行ボタンを押すと、ブラウザーのコンソールに次のような結果が表示されます。

{
  ...
  "humidity": 60.4,
  ...
}

以上の例ではパラメータが不要なサービスを例に挙げましたが、多くのサービスではパラメータを必要とします。dSymphony.requestAction() は、自由にパラメータを与えることも可能です。

アーキテクチャ

以上で、ユーザー認証、ゲートウェイ登録、アクション実行の一連の流れを解説してきましたが、とりわけゲートウェイ登録からアクション実行では、紹介したメソッドが必要な処理を自動的に行い、Symphony の仕組みを隠ぺいしています。より洗練された処理フローをダッシュボードで実現するためには、Symphony が内部で保持しているデータの構造、そして、Web API を知る必要があります。以下、ゲートウェイの発見からサービス実行に至るまでの詳細な処理フローを解説します。

前述のチートリアルでは、dSymphony.setupGateway() メソッドを使って、いきなりゲートウェイが提供するアクションの情報を取得しましたが、この結果を得るためは、いくつかの処理を行っています。

  1. ゲートウェイの登録

    ゲートウェイの電源を入れる、または、スマートフォンのゲートウェイアプリを起動すると、自動的に Symphony にそのゲートウェイが一時的に登録されます。しかし、そのゲートウェイはどのユーザーにも関連付けられておらず、しばらくすると、Symphony から削除されます。

  2. ゲートウェイの検索

    ユーザーがゲートウェイの UUID を指定して、そのゲートウェイを自身のアカウントと関連付けます。この関連付けが完了して、初めて自分のゲートウェイとして、そのゲートウェイにアクセスが可能になります。ダッシュボードでは、ユーザーからゲートウェイの UUID を取得し、Symphony から指定の UUID を持ったゲートウェイを検索する必要があります。この処理は searchGateway() メソッドが担います。

  3. ゲートウェイの関連付け

    指定の UUID を持ったゲートウェイが見つかったら、getGateways() メソッドを使って、それがすでに登録済みの UUID かどうかを確認する必要があります。もし未登録のゲートウェイであれば、それをユーザーに関連付けます。この関連付けには registerGateway() メソッドを使います。

  4. デバイスの発見と登録

    ゲートウェイの登録が完了した時点では、まだ Symphony は該当のゲートウェイが扱えるデバイスおよびアクションを認識していません。このデバイスおよびアクションの登録には registerDevice() メソッドを使います。このメソッドは、未登録のデバイスを自動的に登録してしまうモードと、個別に一つずつデバイスを登録するモードがありますが、setupGateway() メソッドは、前者のモードを使っています。もし未登録のデバイスを事前に知りたい場合は、getUnregisteredDevices() メソッドを使うことができます。ここから得られた未登録デバイスの情報をもとに、registerDevice() メソッドを使って 1 つずつ取捨選択しながらデバイス登録することもできます。

  5. アクションの取得

    デバイスの登録が完了したら、そのデバイスがどのようなアクションを提供しているのかを取得する必要があります。前述のデバイス登録の際に使う registerDevice() メソッドのレスポンスには、登録されたデバイスのアクションの情報が含まれます。しかし、デバイス登録後に利用可能なアクションを知りたい場合は getActions() メソッドを使うことができます。

  6. アクションの解析と実行

    アクション情報には、アクションの概要だけでなく、リクエストに必要なパラメータ情報を含んでいます。サービスを利用するためには、このパラメータ情報を解析して、Symphony に対して適切なパラメータを与えてリクエストする必要があります。アクションの実行には、requestAction() メソッドが便利です。アクション ID を指定するだけでアクションを実行することができます。この requestAction() メソッドは、内部的には、ローレベル API の request() メソッドを使っています。もしゲートウェイ配下のデバイスが提供するアクションをきめ細かく制御したい場合は、request() メソッドを使うこともできます。

本来、上記の手順を踏んで Symphony 経由でゲートウェイおよびその先にあるデバイスを操作するわけですが、前述のチュートリアルで紹介した setupGateway() メソッドは、上記手順の 2 ~ 5 の処理をまとめて行っています。

このように、チュートリアルで紹介した 統合 API を使って簡単に処理を行うのか、Symphony の Web API と一対一で対応しているそれ以外のメソッドを使うのかは、状況に応じて使い分けてください。

Symphony には、ゲートウェイやデバイスやサービスを扱う API のほか、以下の機能も用意されています。

  • ユーザー管理

    自分のアカウントの修正や削除、また、共有ユーザーの登録や削除などが提供されています。共有ユーザーを登録することで、サービスをその共有ユーザーに利用させることが可能になります。

  • ロール管理

    前述の共有ユーザーに対して、利用可能なサービスを制限することができます。また、そのサービスを利用できる期間なども詳細に設定することができます。

  • アーカイブ管理

    ゲートウェイの先のデバイスからの応答を Symphony に保存しておくことができます。保存の開始、取得、停止といった API が提供されています。

  • チーミング管理

    もし 2 つのゲートウェイが同じデバイスを認識していると、Symphony では別々のデバイスとして認識されます。しかし、チーミング機能を使うと、それら 2 つをあたかも 1 つのデバイスであるかのように扱うことができます。

  • イベントメッセージ

    デバイスによっては、リクエスト・レスポンス型のサービスだけでなく、非同期に情報を通知してくるサービスもあります。本 SDK は、この非同期のイベントメッセージを受信する枠組みを提供しています。