初期化コードの実装(ゲートウェイ)

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

このページは、Thing Interaction Framework の ゲートウェイ 機能を使用して、ゲートウェイやエンドノードを初期化する方法を示しています。スタンドアローンの Thing として初期化する場合は、初期化コードの実装 の手順を使用してください。

まずは、ゲートウェイを初期化し、エンドノードが追加されるごとにエンドノードを初期化します。初期化処理が完了すると、アプリケーション上の Thing に示すように、ゲートウェイと複数のエンドノードが Kii Cloud 上に作成され、それらがモバイルアプリの操作ユーザーと紐付いた状態になります。

初期化を行うには、ゲートウェイやエンドノードと、モバイルアプリとの間で、ゲートウェイのユーザー名とパスワードを共有しておく必要があります。これらはゲートウェイの製品本体に貼り付けたシールやラベルを見てモバイルアプリに手入力したり、Bluetooth などの近距離無線通信によって共有したりすることで、モバイルアプリ側の情報として用意しておきます。

ゲートウェイの初期化

ゲートウェイアプリ、エンドノードアプリとも、ゲートウェイの Thing の初期化処理を次の手順で実行します。

  1. Kii Cloud SDK の初期化

  2. ThingIFAPI の取得

  3. GatewayAPI の取得と接続

  4. 初期登録の実行

ここでは、SDK での API の構成 に示す API インスタンスのうち、ゲートウェイの ThingIFAPI インスタンスと、GatewayAPI インスタンスを取得します。これらはゲートウェイ本体そのものの操作を行うための API クラスです。エンドノード用の API クラスは後のエンドノードアプリ用の手順によって取得します。

初期化手順のコードを読み解く際は、機能ガイドの ゲートウェイの初期登録 の図と見比べながらコードを確認すると、全体の流れが理解しやすくなります。

Kii Cloud SDK の初期化

アプリケーションクラスから、以下の処理を実行します。これはモバイルアプリの起動時に呼び出されます。

アプリケーションクラスの名前は、Thing-IF SDK の導入手順 において、AndroidManifest.xml で指定したものです。

// The MobileApp class should be declared in your mobile app's AndroidManifest.xml.
public class MobileApp extends Application {
  @Override
  public void onCreate() {
    super.onCreate();
    // Initialize the Kii Cloud SDK. Call this method before any other Kii SDK API calls.
    // This method can be called multiple times.
    Kii.initialize(getApplicationContext(), "___APPID___", "___APPKEY___", Kii.Site.JP, false);
  }
}

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

第 5 引数の false は、Kii Cloud SDK のアプリ分析機能を使用しないことを意味します。アプリから Kii Cloud SDK の機能を本格的に使用し、アプリ分析機能を併用する場合を除いて false を指定します。

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

ThingIFAPI の取得

次に、ゲートウェイを操作するために Thing Interaction Framework にリクエストを行うための ThingIFAPI インスタンスを取得します。この処理は、上記 Kii Cloud SDK の初期化後であれば、アプリ中のどの位置で実行しても問題ありません。

ThingIFAPI apiGateway;

// Instantiate your application on Kii Cloud.
KiiApp app = new KiiApp("___APPID___", "___APPKEY___", Site.JP);

// Instantiate a ThingIFAPIBuilder object.
ThingIFAPIBuilder ib = ThingIFAPIBuilder.newBuilder(getApplicationContext(), app, owner);

// Set a tag for the ThingIFAPIBuilder instance.
ib.setTag("gateway");

// Add a schema to the ThingIFAPIBuilder instance.
ib.addSchema(schema);

// Instantiate a Thing-IF API from the ThingIFAPIBuilder instance.
apiGateway = ib.build();

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

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

    Site の代わりに api-jp.kii.com のようなサーバーのホスト名を指定して初期化することもできます。詳細は Javadoc をご覧ください。

  • owner はゲートウェイのオーナーとなるユーザーを表します。取得方法は オーナーの定義(ゲートウェイ) をご覧ください。

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

  • schema はスキーマ定義を表します。設定方法は スキーマの定義(ゲートウェイ) をご覧ください。

初期化が完了すると、API を実装しているインスタンスを取得できます。ThingIFAPIBuilderbuild メソッドを呼び出すと、Thing-IF SDK が初期化されて ThingIFAPI インスタンスが返されます。ThingIFAPI インスタンスは、クラスのフィールドや Activity クラスに保持するなどして、後続の処理で呼び出せる状態にしておきます。また、初期化済みの情報の保存と復元(ゲートウェイ) に示す方法によって、プロセス再起動時にインスタンスを再生成したり、保存や読み込みを行ったりできます。

ibsetTag メソッドでは、各 ThingIFAPI を識別するための一意の名前をタグとして与えます。タグは saveInstanceloadFromStoredInstance によって保存や読み込みを行う際にインスタンスを識別するために使用します。エンドノードでは、後述の初期化処理で "gateway" とは異なるタグを付けて識別します。

GatewayAPI の取得と接続

次に、GatewayAPI インスタンスを取得します。このインスタンスは、Wi-Fi 等のローカルネットワークを使ってモバイルアプリからゲートウェイにアクセスする際に必要な API をまとめたオブジェクトです。

GatewayAPI gatewayLocal;

// Instantiate a gateway API object.
Uri gatewayUri = Uri.parse("___GATEWAY_URL___");
gatewayLocal = GatewayAPIBuilder.newBuilder(getApplicationContext(), app, gatewayUri).build();

try {
  // Authenticate a user to the gateway.
  gatewayLocal.login("___GATEWAY_USERNAME___", "___GATEWAY_PASSWORD___");
} catch (ThingIFException e) {
  // Handle the error.
}
  • ゲートウェイの URL、ユーザー名、パスワードを ___GATEWAY_URL______GATEWAY_USERNAME______GATEWAY_PASSWORD___ に指定します。ゲートウェイの URL は、http://192.168.0.10/ のような、モバイルアプリからローカルネットワーク上で Wi-Fi アクセスできるアドレスです。また、ゲートウェイのユーザー名とパスワードは、ゲートウェイエージェントが持つ認証用の情報で、何らかの形でモバイルアプリと共有しておきます。

  • newBuilderapp インスタンスは、ThingIFAPI を初期化した際の KiiApp インスタンスと同じものを指定します。AppID、AppKey などが設定されています。

  • login メソッドを呼び出すと、ゲートウェイにアクセスして認証処理を行います。

初期登録の実行

モバイルアプリからゲートウェイやエンドノードなどの Thing を制御するには、モバイルアプリと Thing を紐付ける操作が必要です。この紐付け操作を初期登録(Onboarding)と呼びます。

初期登録の API を含め、Thing-IF SDK で提供する API はすべてブロッキング API です。ブロッキング API をメインスレッドから呼び出すと、ユーザーインターフェイスが停止する問題を起こします。Thing-IF SDK の API は、実装上の注意点 に挙げるような非同期処理の技術を使うか、自分で作成した作業スレッドから呼び出すようにしてください。

ゲートウェイでは、以下の方法で初期登録を行います。

try {
  // Instantiate the gateway.
  Gateway gateway = gatewayLocal.onboardGateway();

  // Get the thing ID of the gateway.
  String thingID = gateway.getThingID();

  // Set the gateway password.
  String gatewayPassword = "___GATEWAY_PASSWORD___";

  // Onboard the gateway to Thing Interaction Framework.
  apiGateway.onboard(thingID, gatewayPassword);
} catch (ThingIFException e) {
  // Handle the error.
}

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

  1. onboardGateway によって、Wi-Fi 経由でゲートウェイに初期登録の要求を出します。成功すると、Gateway インスタンスが返ります。Gateway インスタンスからは、ゲートウェイの thingID を取得できます。

  2. onboard によって、Thing Interaction Framework に初期登録の要求を出します。これによって、apiGateway の初期化の際に指定したオーナーと、thingID で指定されたゲートウェイが紐づくことになります。

ゲートウェイの初期登録は、ここに示す 1 通りの方法だけをサポートしています。スタンドアローンの Thing では、初期登録をモバイルアプリから行うか、Thing とモバイルアプリの両方から行うかを選択できます。

ここまでの処理が完了すると、ゲートウェイとモバイルアプリの紐付けが完了したことになります。取得できた apiGatewaygatewayLocal を使って後続の処理を行います。

ゲートウェイアプリでは、必要な初期化処理は以上で完了です。エンドノードアプリではこれに加え、次に示すエンドノードの初期化が必要です。

エンドノードの初期化

エンドノードアプリでは、ゲートウェイの初期化後、エンドノードが追加されるごとにその初期化処理を行います。

エンドノードの Thing は次の手順で初期化します。

  1. 未処理リストの取得

  2. 初期登録の実行

  3. ThingIFAPI の取得

  4. デバイスのインストール

  5. ゲートウェイへの完了通知

初期化手順のコードを読み解く際は、機能ガイドの エンドノードの初期登録 の図と見比べながらコードを確認すると、全体の流れが理解しやすくなります。

未処理リストの取得

はじめに、ゲートウェイにアクセスして、初期化処理が未完了となっているエンドノードのリストを取得します。ゲートウェイでは、ゲートウェイには接続済みだが、Thing Interaction Framework への初期登録が行われていないエンドノードの一覧を管理しています。ゲートウェイの API を通して、この一覧を取得できます。

ゲートウェイへのアクセスには、すでに取得している GatewayAPI のインスタンス gatewayLocal を使用します。未処理のエンドノードの一覧を取得し、このうちの 1 件を選択して、後続の初期化処理を行います。

try {
  // Get a list of pending end nodes.
  List<PendingEndNode> pendingEndNodeList = gatewayLocal.listPendingEndNodes();

  for (PendingEndNode pendingEndNode : pendingEndNodeList) {
    String endnodeVendorThingID = pendingEndNode.getVendorThingID();
    String endnodeThingType = pendingEndNode.getThingType();
    JSONObject endnodeProperties = pendingEndNode.getThingProperties();
    // Select a pending end node to onboard.
  }
} catch (ThingIFException e) {
  // Handle the error.
}

listPendingEndNodes を呼び出すと、Thing Interaction Framework に未登録のエンドノードの一覧を List<PendingEndNode> として取得できます。このサンプルコードでは、その一覧を 1 件ずつ処理してそのエンドノードの詳細情報を取得しています。

モバイルアプリでは、処理対象となる PendingEndNode インスタンスを 1 つ決定します。処理対象を決めるため、モバイルアプリのユーザーインターフェイスによって対象のエンドノードをユーザーに選択させたり、すべての未処理エンドノードを順番に 1 件ずつ処理したりする方法が考えられます。

対象のエンドノードをユーザーに選択させる場合、対象のエンドノードを識別する情報として、エンドノードの Thing タイプと Thing 情報を使用できます。これらは、エンドノードをゲートウェイに接続する際、モバイルアプリの仕様に合わせて自由に使用できる値です。たとえば、endnodeProperties のフィールドとして、製品のシリアル番号や、E26 型 Kii スマート LED [ABC-123] のような製品名を持たせることができます。これらを画面に表示するなどして、初期化対象の PendingEndNode インスタンスを 1 つ決めます。

初期化対象の PendingEndNode インスタンスが決定したら、次の処理に進みます。

初期登録の実行

次に、エンドノードの Thing、モバイルアプリ(操作しているユーザー)、ゲートウェイの 3 つを紐付ける初期登録の操作を行います。

初期登録を行う前に、エンドノードのパスワードをモバイルアプリに用意します。これは、エンドノードを扱う際に Thing Interaction Framework 上のセキュリティを向上するためのもので、ユーザーインターフェイス等で入力しても、モバイルアプリ内部で決めても構いません。ただし、エンドノードのパスワードが漏洩すると不正な操作が行われるおそれがあり、紛失するとアクセスできなくなる問題が発生するため、安全な方法で管理する必要があります。

エンドノードでは、以下のエンドノード専用の API を使って初期登録を行います。

EndNode endNode;
try {
  // Set the end node password.
  String endNodePassword = "123ABC";

  // Set the data grouping interval option.
  OnboardEndnodeWithGatewayOptions.Builder builder = new OnboardEndnodeWithGatewayOptions.Builder();
  builder.setDataGroupingInterval(DataGroupingInterval.INTERVAL_15_MINUTES);
  OnboardEndnodeWithGatewayOptions options = builder.build();

  // Onboard the end node.
  endNode = apiGateway.onboardEndnodeWithGateway(pendingEndNode, endNodePassword, options);
} catch (ThingIFException e) {
  // Handle the error.
}

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

  • pendingEndNode未処理リストの取得 で決定した初期化対象のエンドノードです。
  • endNodePassword: 初期化対象のエンドノードのパスワードです。何らかの形でモバイルアプリに用意しておきます。
  • setDataGroupingInterval():ステート履歴を保存する場合、履歴をグループ化する間隔を指定します。指定のない場合はステート履歴は保存されません。指定可能な値は INTERVAL_1_MINUTE、INTERVAL_15_MINUTES、INTERVAL_30_MINUTES、INTERVAL_1_HOUR、INTERVAL_12_HOURS のいずれかです。詳しくは こちら をご参照ください。

初期登録が完了すると、初期登録済みのエンドノードを表す EndNode インスタンスを取得できます。これは次のステップで利用します。

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

ThingIFAPI の取得

各エンドノードに対して Thing Interaction Framework 経由でリクエストを行うための ThingIFAPI インスタンスを取得します。

ここでは、取得済みのインスタンスを apiEndNode1 としていますが、実際のプログラムではゲートウェイに接続されているエンドノード数分だけ ThingIFAPI インスタンスを生成します。Map や 配列など、複数のエンドノードを扱えるデータ構造で管理する方法をおすすめします。

ThingIFAPI apiEndNode1;

// Instantiate a ThingIFAPIBuilder object.
ThingIFAPIBuilder ib = ThingIFAPIBuilder.newBuilder(getApplicationContext(), app, owner);

// Specify the end node to associate with a new Thing-IF API.
ib.setTarget(endNode);

// Set a tag for the ThingIFAPIBuilder instance.
ib.setTag("endnode1");

// Add a schema to the ThingIFAPIBuilder instance.
ib.addSchema(schema);

// Instantiate a Thing-IF API from the ThingIFAPIBuilder instance.
apiEndNode1 = ib.build();

取得方法は、ゲートウェイの ThingIFAPI の取得 と同様ですが、エンドノードの初期化では、以下の点にご注意ください。

  • app には、ゲートウェイの初期化と同じインスタンスを指定してください。エンドノードアプリから見たとき、ゲートウェイとエンドノードは同じアプリケーション内で動作します。

  • owner には、通常、ゲートウェイや他のエンドノードの初期化で指定したユーザーを指定し、同じオーナーの権限で操作します。

  • setTarget メソッドによって、初期化される ThingIFAPI を初期登録済みの EndNode と紐付けます。

  • ibsetTag メソッドでは、タグ "endnode1" を指定しています。ここで指定しているタグは、saveInstanceloadFromStoredInstance によって保存や読み込みを行う際にインスタンスを識別するために使用するものです。ゲートウェイや他のエンドノードとは異なる一意の文字列を指定してください。初期化済みの情報の保存と復元(ゲートウェイ) のコード例もご覧ください。

  • schema は初期化しようとしているエンドノードが使用するスキーマ定義を指定します。ゲートウェイや他のエンドノードとは異なるスキーマを設定することができます。schema の設定方法は スキーマの定義(ゲートウェイ) をご覧ください。

デバイスのインストール

エンドノードでは、コマンドを送信した際にエンドノードからの応答を受け取れるよう、デバイスのインストールを行います。この操作により、オーナーと FCM のデバイストークンが Kii Cloud 上で紐付きます。

デバイスのインストール

デバイスをインストールするには、エンドノードのそれぞれに対して、Thing-IF SDK の初期化で取得した ThingIFAPI のインスタンスを使って以下のように実行します。パラメーターについて詳しくは、後の実装例をご覧ください。

try {
  // Register the device token for the thing owner to Kii Cloud.
  apiEndNode1.installPush(token, PushBackend.GCM);
} catch (ThingIFException e) {
  // Handle the error.
}

デバイスのインストールが完了すると、ThingIFAPI 作成時に指定したオーナーは、指定されたデバイストークンと紐付けて Thing Interaction Framework に登録されます。既存のデバイストークンはインストールによって上書きされるため、以前紐付いていたオーナーへのプッシュ通知はこのデバイスに届かなくなります。

実装例

この例では、Android (FCM) プッシュ通知設定チュートリアルコード を Thing-IF 向けに変更するものとして説明します。プッシュ通知チュートリアルの例では、MainActivity のメインスレッドからインストール処理を実行する必要があるため、JDeferred を使ってデバイスのインストール処理を非同期で実行する例を示します。

Hello Thing-IF チュートリアル のように、API 呼び出しのため作業スレッドを作成している場合は、JDeferred を使った実装を行わず、作業スレッドから installPush を呼び出せば目的の処理を実装できます。

まずは、JDeferred による Promise を使用して、次のような API 実行用のメソッドを用意します。

private Promise<Void, Throwable, Void> installFCMPush(final ThingIFAPI api, final String token) {
  return mAdm.when(new DeferredAsyncTask<Void, Void, Void>() {
    @Override
    protected Void doInBackgroundSafe(final Void... params) throws Exception {
      // Register the device token for the thing owner to Kii Cloud.
      api.installPush(token, PushBackend.GCM);
      return null;
    }
  });
}

さらに、この処理の呼び出し部分を MainActivity に組み込みます。

private AndroidDeferredManager mAdm = new AndroidDeferredManager();

@Override
protected void onCreate(Bundle savedInstanceState) {
  ......

  // Get a FCM token.
  String fcmToken = FirebaseInstanceId.getInstance().getToken();
  if (fcmToken == null) {
    Toast.makeText(MainActivity.this, "Error FCM is not ready", Toast.LENGTH_LONG).show();
    return;
  }

  // Register the device token for the thing owner to Kii Cloud.
  mAdm.when(installFCMPush(apiEndNode1, fcmToken)
  ).then(new DoneCallback<Void>() {
    @Override
    public void onDone(Void param) {
      Toast.makeText(MainActivity.this, "Succeeded push registration", Toast.LENGTH_LONG).show();
    }
  }).fail(new FailCallback<Throwable>() {
    @Override
    public void onFail(final Throwable tr) {
      Toast.makeText(MainActivity.this, "Error push registration:" + tr.getLocalizedMessage(), Toast.LENGTH_LONG).show();
    }
  });
  ......
}

デバイスのアンインストール

インストールしたデバイスをアンインストールしたい場合は、以下のコードを実行します。

この処理をエンドノードのどれか 1 つで実行すると、全てのエンドノードについて、プッシュ通知が届かなくなります。アンインストール処理は、最後のエンドノードを取り除くような場合に実行してください。

try {
  // Unregister the push notification for the thing owner.
  apiEndNode1.uninstallPush(apiEndNode1.getInstallationID());
} catch (ThingIFException e) {
  // Handle the error.
}

このコードはデバイスのインストールが完了していることを前提としています。getInstallationID メソッドは、installPush でインストールが成功していない場合 null を返します。

成功すると、Thing Interaction Framework からのプッシュ通知がこの端末に届かなくなります。

ゲートウェイへの完了通知

最後に、初期登録が完了したことをゲートウェイに通知します。

try {
  // Notify the gateway of the completion of onboarding.
  gatewayLocal.notifyOnboardingCompletion(endNode);
} catch (ThingIFException e) {
  // Handle the error.
}

endNode には、初期登録の実行結果として得られた EndNode インスタンスを指定します。

機能の実行

以上の操作により、ゲートウェイと各エンドノードの初期化が完了します。初期化の完了時、以下のインスタンスを取得できています。

  • ゲートウェイの ThingIFAPI インスタンス

    ここでは apiGateway として表現しています。Thing Interaction Framework 経由でゲートウェイにアクセスする際に使用します。エンドノードやゲートウェイ自身の管理のために使用します。現在のバージョンでは、新しいエンドノードを初期化するために必要です。

  • ゲートウェイの GatewayAPI インスタンス

    ここでは gatewayLocal として表現しています。Wi-Fi によってゲートウェイに直接アクセスする際に使用します。エンドノードやゲートウェイ自身の管理のために使用します。現在のバージョンでは、新しいエンドノードを初期化するために必要です。

  • エンドノードの ThingIFAPI インスタンス

    ここでは apiEndNode1 として表現しています。複数個のエンドノードを接続した場合は複数個のインスタンスが得られます。

    このインスタンスを使って、エンドノードにコマンドを送信したり、エンドノードのステートを調べたりできます。たとえば、apiEndNode1 にコマンドを送信すると、Thing Interaction Framework は接続しているゲートウェイにコマンドを送信し、そのエンドノードはゲートウェイ経由でコマンドを受け取ることができます。

    実際にコマンドを送信したりステートを受信したりする方法は、コマンドの実行ステートの参照トリガー を参照してください。この際、各サンプルコードの api は、操作対象となるエンドノードの apiEndNode1 に読み替えてください。