初期化コードの実装

SDK を導入するアプリケーションから初期化処理を実行する必要があります。

初期化処理は次の順番で実行するように実装します。

  1. Kii Cloud SDK の初期化

  2. Thing-IF SDK の初期化(オーナー定義とスキーマ定義を含む)

  3. プッシュ通知の初期化

  4. 初期登録の実行

Kii Cloud SDK の初期化

Web アプリの起動時に以下の処理を実行します。HTML ページの window.onload ハンドラーやフレームワークの初期化ハンドラーでの実行が適切です。

  • // Initialize the Kii Cloud SDK. Call this method before any other Kii SDK API calls.
    kii.Kii.initializeWithSite("___APPID___", "___APPKEY___", kii.KiiSite.JP);
    
    // Initialize other components.
    ...
  • // Initialize the Kii Cloud SDK. Call this method before any other Kii SDK API calls.
    Kii.initializeWithSite("___APPID___", "___APPKEY___", KiiSite.JP);
    
    // Initialize other components.
    ...

___APPID______APPKEY___ の項目は、開発者ポータルにて取得した AppID と任意の値を設定してください(アプリケーションの作成 を参照してください)。

AppID をクライアントアプリに埋め込んでも、アクセス制御を正しく行えば安全性は確保できます。詳細は、セキュリティ をご覧ください。

Thing-IF SDK の初期化

次に、Thing-IF SDK を初期化します。この処理は、上記 Kii Cloud SDK の初期化後であれば、アプリ中のどの位置で実行しても問題ありません。

  • // Instantiate your application on Kii Cloud.
    const app = new ThingIF.App("___APPID___", "___APPKEY___", ThingIF.Site.JP);
    
    // Instantiate a Thing-IF API from the ThingIFAPIBuilder instance.
    const api = new ThingIF.ThingIFAPI(owner, accessToken, app);
  • // Instantiate your application on Kii Cloud.
    var app = new ThingIF.App("___APPID___", "___APPKEY___", ThingIF.Site.JP);
    
    // Instantiate a Thing-IF API from the ThingIFAPIBuilder instance.
    var api = new ThingIF.ThingIFAPI(owner, accessToken, app);

ソースコード中、以下の情報を指定します。

  • ___APPID______APPKEY___ の項目は、開発者ポータルにて取得した AppID と任意の値を設定してください(アプリケーションの作成 を参照してください)。

    Site の代わりに http://api-jp.kii.com のようなサーバーのベース URL を指定して初期化することもできます。

  • owner は Thing のオーナーとなるユーザーを、accessToken はそのユーザーのアクセストークンを表します。取得方法は オーナーの定義 をご覧ください。

    ユーザーの指定方法は、モバイルアプリのデザインによって様々な形式が考えられます。本ガイドでは、仮ユーザー(Pseudo User)を使って明示的なユーザー作成やログインを行わずにユーザーを利用する方法を案内しています。明示的にログイン操作を行うデザインを採用した場合は、ログイン画面を用意し、ログイン処理の完了時に Thing-IF SDK を初期化することになります。

作成した ThingIFAPI インスタンスは、クラスのフィールドに保持するなどして、後続の処理で呼び出せる状態にしておきます。なお、Thing-IF SDK for JavaScript では、他のプラットフォームにある loadFromStoredInstance に相当する機能がないため、初期化済みの ThingIFAPI インスタンスをストレージに保存しておくことはできません。

プッシュ通知の初期化

Web アプリは、プッシュ通知によって Thing からの応答を受け取ります。このプッシュ通知は WebSocket 上の MQTT によって実現します。

事前に、プッシュ通知の導入手順 に示した手順によって MQTT.js を利用可能にしておきます。

モバイルアプリでのプッシュ通知はユーザーが受け取るため、オーナーの定義 に示す方法でオーナーとなるユーザーをログイン状態にしておく必要があります。

オーナーのログイン後、以下のように Kii Cloud SDK と MQTT.js の API を呼び出して、MQTT のコネクションを確立します。

  • // Configure the push notification in production mode.
    const development = false;
    
    // Set up an MQTT endpoint for the logged-in user to Kii Cloud.
    kii.KiiUser.getCurrentUser().pushInstallation().installMqtt(development).then((response) => {
      const installationID = response.installationID;
      return kii.KiiUser.getCurrentUser().pushInstallation().getMqttEndpoint(installationID);
    }).then((response) => {
      const mqttTopic = response.mqttTopic;
    
      const endpoint =  "wss://" + response.host + ":" + response.portWSS + "/mqtt";
      const client = mqtt.connect(endpoint, {
        username: response.username,
        password: response.password,
        clientId: mqttTopic,
      });
    
      // Connect to the MQTT endpoint.
      client.on("connect", () => {
      console.log("Connected to MQTT server");
        client.subscribe(mqttTopic, () => {
          console.log("Subscribed to the MQTT topic");
        });
      });
    
      // Receive a push messsage.
      client.on("message", (topic, message, packet) => {
        if (topic === mqttTopic) {
          console.log("A message arrived");
        }
      });
    
      // Receive an error.
      client.on("error", (error) => {
        console.log("Error in MQTT: " + error);
      });
    }).catch((error) => {
      // Handle the error.
    
      // Get the installation ID for the failed getMqttEndpoint() method.
      const thePushInstallation = error.target;
    
      const errorString = error.message;
    });
  • // Configure the push notification in production mode.
    const development = false;
    
    // Set up an MQTT endpoint for the logged-in user to Kii Cloud.
    KiiUser.getCurrentUser().pushInstallation().installMqtt(development).then(
      function(response) {
        var installationID = response.installationID;
        return KiiUser.getCurrentUser().pushInstallation().getMqttEndpoint(installationID);
      }
    ).then(
      function(response) {
        var mqttTopic = response.mqttTopic;
    
        var endpoint =  "wss://" + response.host + ":" + response.portWSS + "/mqtt";
        var client = mqtt.connect(endpoint, {
          username: response.username,
          password: response.password,
          clientId: mqttTopic,
        });
    
        // Connect to the MQTT endpoint.
        client.on("connect", function() {
          console.log("Connected to MQTT server");
          client.subscribe(mqttTopic, function() {
            console.log("Subscribed to the MQTT topic");
          });
        });
    
        // Receive a push messsage.
        client.on("message", function(topic, message, packet) {
          if (topic === mqttTopic) {
            console.log("A message arrived");
          }
        });
    
        // Receive an error.
        client.on("error", function(error) {
          console.log("Error in MQTT:" + error);
        });
      }
    ).catch(
      function(error) {
        // Handle the error.
    
        // Get the installation ID for the failed getMqttEndpoint() method.
        var thePushInstallation = error.target;
    
        var errorString = error.message;
      }
    );

ここでは以下の処理を行っています。

  1. MQTT エンドポイントを取得します。

    プッシュ通知を受け取るユーザーの pushInstallation().installMqtt() を呼び出して、MQTT エンドポイントのインストールを行います。installMqtt() の引数 development は、プッシュ通知を受け取るネットワークが、開発環境か配布環境かを指定しますが、Thing Interaction Framework では両方の環境にプッシュメッセージが送信されるため、どちらを選択しても問題ありません。

  2. MQTT.js を使って MQTT のコネクションを確立します。

    エンドポイントを取得すると、response として、以下に示すMQTT エンドポイントの情報を取得できます。これらの条件により、mqtt.connect() で MQTT ブローカーに接続します。

    接続に必要な情報 設定する値
    接続先ホスト名 取得した MQTT エンドポイントの host プロパティの値
    接続先ポート番号 取得した MQTT エンドポイントの portTCP プロパティの値(TCP 接続)または portSSL プロパティの値(SSL/TLS 接続)
    WebSocket 接続用ポート番号 取得した MQTT エンドポイントの portWS プロパティの値(TCP 接続)または portWSS プロパティの値(SSL/TLS 接続)
    CONNECT 要求の Keep alive timer アプリの実装に合わせて送信(キープアライブタイマー 参照)
    CONNECT 要求の Client identifier 取得した MQTT エンドポイントの mqttTopic プロパティの値
    CONNECT 要求の Username 取得した MQTT エンドポイントの username プロパティの値
    CONNECT 要求の Password 取得した MQTT エンドポイントの password プロパティの値
    SUBSCRIBE 要求の Topic name 取得した MQTT エンドポイントの mqttTopic プロパティの値

    通常、Web アプリなど、ブラウザー上で使用する場合は portWSS によって WebSocket 上のコネクションを利用します。portTCPportSSL は Web ブラウザーから使用できません。

    なお、Kii Cloud の MQTT では、仕様上 1 人のユーザーからは 1 つの MQTT コネクションしか生成できません。複数の Web アプリを同時に起動しても、接続できるコネクションは 1 つだけであることにご注意ください。

    Web アプリを同時に起動すると、使用する MQTT ライブラリーによっては、コネクションの切断と再接続を繰り返す動きになるものがあります。再接続の頻度をチェックして接続エラーにするような処理が必要になる場合があります。
    MQTT.js でもこの動きになるため、接続エラーにする実装を検討してください。

  3. MQTT.js の各種ハンドラーを設定します。

    サンプルコードでは MQTT.js のハンドラーとして以下の処理を登録しています。

    • 接続完了時の処理として、connect イベントを登録します。ここでは、MQTT トピックを講読します。
    • PUBLISH メッセージを受信したときの処理として、message イベントを登録します。ハンドラー内に実装すべき処理の詳細は コマンドリザルトの受信 をご覧ください。
    • MQTT でエラーが発生したときの処理として、error イベントを登録します。

    上のサンプルコードでは、MQTT.js のイベントは console.log() の呼び出しだけを行っています。動作の確認後、これらは Web アプリに合わせて書き換えてください。

    PUBLISH コマンドは様々な目的で受信するため、サーバー側からの PUBLISH コマンドを受け取った際には、必ず MQTT トピック名をチェックするように実装してください。また、未知の MQTT トピック名を持つ PUBLISH コマンドは、将来の拡張のため無視するように実装してください。

    Thing-IF SDK で受け取る MQTT トピック名は、初期化の際に SUBSCRIBE コマンドで講読した MQTT トピックの名前です。

キープアライブタイマー

MQTT では、コネクションが切れていないことを確認するために死活監視のプロトコルが定められています。

プロトコル上は、CONNECT 要求で送信した Keep alive timer 値の 1.5 倍の時間以内に、クライアントから何らかのメッセージを送信しないと、コネクションは自動的に切断されます。この時間内にクライアントからのメッセージ送信がない場合、PINGREQ リクエストを送信する必要があります。

PINGREQ リクエストの送信処理の実装方法はライブラリーによって異なります。ライブラリー内部で自動的に送信されるものや、プログラム側で送信処理を書く必要があるものがあります。実装方法は使用する MQTT ライブラリーのドキュメントを参照してください。MQTT.js ではライブラリー内部で自動的に送信するため、特別な制御は不要です。

初期登録の実行

モバイルアプリから Thing を制御するには、モバイルアプリと Thing を紐付ける操作が必要です。この紐付け操作を 初期登録(Onboarding) と呼びます。

初期登録には、モバイルアプリから紐付ける方法と、Thing とモバイルアプリ両方から紐付ける方法の 2 通りがあります。いずれの方法でも同じ結果が得られますが、双方で共有すべき情報が異なります。Thing 側の実装も含めて検討し、どちらを採用するかを決めます。

ここでは、以下のどちらか一方の手順を実行します。

サービス全体での初期登録の流れや手順の決定方法の詳細は、機能ガイドの 初期登録 をご覧ください。

初期登録を行わずに ThingIFAPI を使って初期登録以外の処理(コマンドの実行やステートの取得など)を開始すると、エラーになります。

モバイルアプリから紐付ける場合

この方式では、モバイルアプリ上で Thing Interaction Framework への紐付けリクエストをまとめて行います。

機能ガイドに示すとおり、この方法では初期登録の実装がシンプルになりますが、モバイルアプリと Thing との間で通信手段を確保する必要があります。

ステップ 1:モバイルアプリからの初期登録

モバイルアプリからの初期登録を行うため、初期登録に必要な情報を Thing から受け取ります。下記に示すように Thing の vendorThingID と thingPassword が必要です。

モバイルアプリに通知を行う方法は任意です。転送方法の例は、こちら をご覧ください。

モバイルアプリで初期登録を実行するには、以下の処理を行います。

  • // Set the thing credentials.
    const vendorThingID = "nbvadgjhcbn";
    const thingPassword = "123456";
    
    // Set onboarding options.
    const thingType = "AirConditioner";
    const properties = {};
    const interval = ThingIF.DataGroupingInterval.INTERVAL_15_MINUTES;
    const onboardRequest = new ThingIF.OnboardWithVendorThingIDRequest(vendorThingID, thingPassword, null, thingType, properties, null, interval);
    
    // Onboard the thing.
    api.onboardWithVendorThingID(onboardRequest).then((result: ThingIF.OnboardingResult) => {
      const thingID: string = result.thingID;
      const thingAccessToken: string = result.accessToken;
    }).catch((error: ThingIF.ThingIFError) => {
      // Handle the error.
    });
  • // Set the thing credentials.
    var vendorThingID = "nbvadgjhcbn";
    var thingPassword = "123456";
    
    // Set onboarding options.
    var thingType = "AirConditioner";
    var properties = {};
    var interval = ThingIF.DataGroupingInterval.INTERVAL_15_MINUTES;
    var onboardRequest = new ThingIF.OnboardWithVendorThingIDRequest(vendorThingID, thingPassword, null, thingType, properties, null, interval);
    
    // Onboard the thing.
    api.onboardWithVendorThingID(onboardRequest).then(
      function(result) {
        var thingID = result.thingID;
        var thingAccessToken = result.accessToken;
      }
    ).catch(
      function(error) {
        // Handle the error.
      }
    );

ここでは以下の値を設定しています。

  • vendorThingID:ベンダーが定義した Thing の ID です。詳細は こちら をご覧ください。アプリケーション内で一意であれば、200 文字までの英数字、ハイフン、アンダースコアおよびピリオドが利用可能です。なお、このフィールド値は後で変更できません。
  • thingPassword:Thing のパスワードです。Thing Interaction Framework 上に登録された Thing の領域をセキュアにするため、Thing ごとに異なるパスワードを設定するのが基本です。一旦設定したパスワードは変更できません。
  • thingType:Thing タイプです。100 文字までの英数字、ハイフン、アンダースコアおよびピリオドが利用可能です。スキーマ で設計したものを指定します。
  • properties:Thing の属性を JSONObject で指定できます。Kii Cloud SDK を併用する場合に利用する項目のため、ここでは空の JSONObject を指定します。
  • interval:ステート履歴を保存する場合、履歴をグループ化する間隔を指定します。指定のない場合はステート履歴は保存されません。指定可能な値は DataGroupingInterval に定義されている INTERVAL_1_MINUTE、INTERVAL_15_MINUTES、INTERVAL_30_MINUTES、INTERVAL_1_HOUR、INTERVAL_12_HOURS のいずれかです。詳しくは こちら をご参照ください。

実行すると、初期登録した Thing の thingID とアクセストークンを取得できます。

なお、初期登録を一旦行うと、その端末で thingTypepropertiesinterval を指定しても無視されます。

モバイルアプリからの初期登録が行われるまで、ステート履歴は利用できない点にご注意ください。初めのモバイルアプリが紐付くまでの間に Thing はステートをアップロードできますが、そのステートは履歴に保存されません。

ステップ 2:Thing 側の初期化

モバイルアプリからの初期登録では、登録の結果取得できた値を Thing 側に転送する必要があります。

上記のサンプルコードによって初期登録を行うと、モバイルアプリでは Promise の then() の関数より、次の 2 つの値を受け取ることができます。

  • thingID:登録した Thing の thingID
  • thingAccessToken:登録した Thing のアクセストークン

これらを Thing に転送します。Thing 側では、受け取った値を使って初期化を行います(Thing 側では Thing Interaction Framework にアクセスせずに初期登録が完了します)。詳細は こちら をご参照ください。

アクセストークンはパスワードと同様に機密情報であるため、万一、漏洩すると、その Thing は他のユーザーによって制御される恐れがあります。転送には安全な手段を使用してください。

Thing とモバイルアプリ両方から紐付ける場合

この方式では、まず Thing から Thing Interaction Framework への紐付けリクエストを行い、次にモバイルアプリからの紐付けリクエストを行います。

実際にはどちらを先に実行しても問題ありませんが、両方の初期登録が完了するまでコマンドの送信やステートのやりとりは実行できません。

機能ガイドに示すとおり、この方法では、モバイルアプリと Thing の両方で Thing Interaction Framework にアクセスして初期登録を行う必要がありますが、モバイルアプリと Thing の間で直接の通信を行う必要はありません。

ステップ 1:Thing からの初期登録

Thing からの初期登録を行い、ステートの登録やコマンドの受信ができるようにします。

詳細は こちら をご覧ください。

ステップ 2:モバイルアプリからの初期登録

次にモバイルアプリからの初期登録を行い、モバイルアプリからのコマンド送信やステートの取得ができるようにします。

以下の処理を行います。

  • // Set the thing credentials.
    const vendorThingID = "nbvadgjhcbn";
    const thingPassword = "123456";
    
    // Set the data grouping interval option.
    const interval = ThingIF.DataGroupingInterval.INTERVAL_15_MINUTES;
    const onboardRequest = new ThingIF.OnboardWithVendorThingIDRequest(vendorThingID, thingPassword, null, null, null, null, interval);
    
    // Onboard the thing.
    api.onboardWithVendorThingID(onboardRequest).then((result: ThingIF.OnboardingResult) => {
      const thingID: string = result.thingID;
      const thingAccessToken: string = result.accessToken;
    }).catch((error: ThingIF.ThingIFError) => {
      // Handle the error.
    });
  • // Set the thing credentials.
    var vendorThingID = "nbvadgjhcbn";
    var thingPassword = "123456";
    
    // Set the data grouping interval option.
    var interval = ThingIF.DataGroupingInterval.INTERVAL_15_MINUTES;
    var onboardRequest = new ThingIF.OnboardWithVendorThingIDRequest(vendorThingID, thingPassword, null, null, null, null, interval);
    
    // Onboard the thing.
    api.onboardWithVendorThingID(onboardRequest).then(
      function(result) {
        var thingID = result.thingID;
        var thingAccessToken = result.accessToken;
      }
    ).catch(
      function(error) {
        // Handle the error.
      }
    );

ここでは以下の値を設定しています。

  • vendorThingID:ベンダーが定義した Thing の ID です。詳細は こちら をご覧ください。ステップ 1 で設定済の vendorThingID を指定します。
  • thingPassword:Thing のパスワードです。Thing Interaction Framework 上に登録された Thing の領域をセキュアにするため、ユーザーと同様に、Thing ごとに異なるパスワードを設定します。ステップ 1 で設定済のパスワードを指定します。
  • interval:ステート履歴を保存する場合、履歴をグループ化する間隔を指定します。指定のない場合はステート履歴は保存されません。指定可能な値は DataGroupingInterval に定義されている INTERVAL_1_MINUTE、INTERVAL_15_MINUTES、INTERVAL_30_MINUTES、INTERVAL_1_HOUR、INTERVAL_12_HOURS のいずれかです。詳しくは こちら をご参照ください。

実行すると、初期登録した Thing の thingID とアクセストークンを取得できます。

なお、API 上は、Thing 側で取得した thingID を Bluetooth などでデバイスに転送し、vendorThingID の代わりに thingID を指定してモバイルアプリ側の初期登録を実行することもできます。

モバイルアプリからの初期登録が行われるまで、ステート履歴は利用できない点にご注意ください。初めのモバイルアプリが紐付くまでの間に Thing はステートをアップロードできますが、そのステートは履歴に保存されません。