RESTデバイスインテグレーション

概要

RESTはHTTP(S)およびTCPを基本とする、非常にシンプルでセキュアなプロトコルです。現在、非常にシンプルなデバイスから大規模なITに至るまで、すべてのネットワーク・プログラミング環境でサポートされている事実上のインターネット標準となっています。RESTを紹介している多くの本の中の1つにRESTful Web Servicesがあります。

このセクションでは、Things Cloud のRESTインターフェースを使用してデバイスをThings Cloudに統合する方法を説明します。

この説明は、「リファレンス ガイド」のデバイスおよびセンサー・ライブラリだけでなく、各インターフェースについて詳しく説明する Things Cloud OpenAPI仕様 と密接にリンクしています。

サポートされている開発ボードを使用する場合は、デバイスガイド内の該当する説明もご覧ください。

Hello REST!

概要

このセクションでは、Things Cloudでデバイス表現を作成する方法と、その後、関連するメジャーメントデータを送信する方法の基本的な例を示します。

すべての手順は、RESTインターフェースを呼び出すことによって実行されます。これらのRESTコールは、CURL ステートメントによってコマンドラインで実行できます。

前提条件

このチュートリアルを実行するには、次の前提条件が満たされているかどうかを確認してください。

RESTコールを実行する

次に、2つのRESTコールのシーケンスを実行します。詳細は次で説明します。

実際には、これらのステップは 「デバイスエージェント」 によって実行されます。

ステップ1は、デバイスが初めてThings Cloudに接続されたときに1回だけ実行されます。

その後、このステップを実行したときに返される内部IDによってデバイスを参照することで、そのデバイスに関連するアクションを実行することができます。

新しいデバイスの作成

Things Cloudのインベントリに新しいデバイスを作成するには、次のRESTリクエストが必要です。

POST /inventory/managedObjects HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json
Accept: application/vnd.com.nsn.cumulocity.managedobject+json
Authorization: Basic <<Base64 encoded credentials <tenant ID>/<username>:<password> >>
...
{
    "c8y_IsDevice" : {},
    "name" : "HelloWorldDevice"
}

このコールは、次のCURLステートメントを実行することによって実行できます。

curl -v -u <username>:<password> \
   -H 'Accept: application/vnd.com.nsn.cumulocity.managedobject+json' \
   -H 'Content-type: application/vnd.com.nsn.cumulocity.managedobject+json' \
   -X POST \
   -d '{"c8y_IsDevice":{},"name":"HelloWorldDevice"}' \
   https://<Things Cloud tenant domain>/inventory/managedObjects

Things Cloudに登録するときに、<username><password><tenant-ID>を適切な認証情報に置き換えます。 Things Cloud Web GUIへのアクセスに使用するものと同じ認証情報を使用してRESTコールを実行することができます。

次のようなレスポンスが表示されます。

HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json; charset=UTF-8; ver=0.9
Authorization: Basic <<Base64 encoded credentials <tenant ID>/<username>:<password> >>
...
{
    "id": "1231234"
    "lastUpdated": "2014-12-15T14:58:26.279+01:00",
    "name": "HelloWorldDevice",
    "owner": "<username>",
    "self": "https://.../inventory/managedObjects/1231234",
    "c8y_IsDevice": {},
    ...
}

デバイスを作成する場合、Things CloudはIDを生成します。このIDは、デバイスを参照するために以降のコールで必要になります。 このIDは、レスポンスの中に「ID」属性と値のペアとして存在します。

メジャーメントデータの送信

デバイスが作成された後、メジャーメントデータを送信できます。

この例では、特定の時間に収集された摂氏単位の温度メジャーメントを送信します。

POST /measurement/measurements
Content-Type: application/vnd.com.nsn.cumulocity.measurement+json
Accept: application/vnd.com.nsn.cumulocity.measurement+json
...
{
    "c8y_TemperatureMeasurement": {
        "T": {
            "value": 21.23,
            "unit":"C"
        }
    },
    "time": "2014-12-15T13:00:00.123+02:00",
    "source": {
        "id": "1231234"
    },
    "type":"c8y_PTCMeasurement"
}

idの値を、最初の手順で取得した適切な値に置き換えます。

さらに、時間値を最近のタイムスタンプに更新し、後でThings Cloud UIでメジャーメントを見つけやすくする必要があります。 Swagger/OpenAPI Specificationdate-timeで説明されているタイムスタンプ値のデータ形式に注意してください。

curl -v -u <username>:<password> \
   -H 'Accept: application/vnd.com.nsn.cumulocity.measurement+json' \
   -H 'Content-type: application/vnd.com.nsn.cumulocity.measurement+json' \
   -X POST \
   -d '{"c8y_TemperatureMeasurement":{"T":{"value":21.23,"unit":"C"}},"time":"2014-12-15T13:00:00.123+02:00","source":{"id":"1231234"},"type":"c8y_PTCMeasurement"}' \
   https://<Things Cloud tenant domain>/measurement/measurements/

このリクエストに対するレスポンスは次のようになります。

HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.measurement+json; charset=UTF-8; ver=0.9
...
{
    "id": "4711",
    "self": "https://.../measurement/measurements/4711",
    "source": {
        "id": "1231234",
        "self": "https://.../inventory/managedObjects/1231234"
    },
    "time": "2014-12-15T12:00:00.123+01:00",
    "type": "c8y_PTCMeasurement",
    "c8y_TemperatureMeasurement": {
        "T" : {
            "unit" : "C",
            "value" : 21.23
        }
    }
}

必要に応じて、メジャーメントの送信を繰り返すことができます。リクエストを再送信する前に、タイムシリーズを作成するためにタイムスタンプ(属性「time」の値)を更新する必要があります。

以上で完了です。Things Cloud UIにデバイス管理アプリケーションを入力し、「すべてのデバイス」ページでデバイスを選択し、「計測値(メジャーメント)」タブに切り替えます。ここにメジャーメントデータが表示されます。

データが表示されない場合は、送信したメジャーメントで使用したタイムスタンプを含めるために、フィルター設定を「直近1週間」などに変更してください。

詳細

ここで示したRESTコールのシーケンスはデバイスインテグレーションで説明した手順を短縮したものにすぎません。 最初のステップ(新規デバイスの作成)は「スタートアップフェーズ」の一部ですが、ステップ2(メジャーメントの送信)はサイクルフェーズを指します。

実際のエージェントの実装に必要な情報については、デバイスインテグレーション をご覧ください。

デバイスインテグレーション

デバイスをThings Cloudに統合するための基本的なライフサイクルは、「Things Cloud コンセプトガイド」のデバイスのインターフェースで説明されています。このセクションでは、このライフサイクルがRESTレベルでどのように実装されるかを説明します。 ライフサイクルは、スタートアップフェーズとサイクルフェーズの2つのフェーズで構成されます。

スタートアップフェーズでは、デバイスをThings Cloudに接続し、インベントリのデバイスデータを更新します。 また、オペレーションに必要なクリーンアップタスクも実行します。次の手順で構成されます。

Startup phase

サイクルフェーズへと続きます。 インベントリを継続的に更新し、メジャーメント、アラーム、イベントを書き込み、必要に応じてオペレーションを実行します。 これは、デバイスの電源が切れるまで実行される、デバイスの「メインループ」となります。 このループは次の手順で構成されます。

Cycle phase

データの参照モデルについては「リファレンスガイド」のデバイス管理ライブラリセンサー・ライブラリ をご覧ください。

スタートアップフェーズ

ステップ 0: デバイスの認証情報をリクエストする

Things Cloudへのすべてのリクエストは認証される必要があり、デバイスからのリクエストも認証される必要があります。個々の認証情報をデバイスに割り当てる場合は、デバイス認証情報APIを使用して新しい認証情報を自動的に生成できます。これを行うには、最初の起動時にAPIを介してデバイスの認証情報をリクエストし、それ以降のリクエストに備えてデバイス上のローカルに保存します。

このプロセスは次のように動作します。

デバイス側の視点から見ると、これは単一のRESTのリクエストです:

POST /devicecontrol/deviceCredentials
Content-Type: application/vnd.com.nsn.cumulocity.devicecredentials+json
Authorization: Basic <<Base64 encoded bootstrap credentials>>
{
  "id" : "0000000017b769d5"
}

デバイスはこのリクエストを繰り返し発行します。ユーザーがデバイスを登録してデバイス管理アプリで承認していない間は、リクエストは「404 Not Found」を返します。デバイスが承認されると、次のレスポンスが返されます:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.devicecredentials+json;charset=UTF-8;ver=...
Content-Length: ...
{
  "id" : "0000000017b769d5",
  "self" : "<<URL of new request>>",
  "tenantId" : "test",
  "username" : "device_0000000017b769d5",
  "password" : "3rasfst4swfa"
}

これで、デバイスはテナントID、ユーザー名、パスワードを使用してThings Cloudに接続できます。ユーザーエイリアスはデバイスではサポートされていません。

テナント名がテナントIDと同じであると想定することはもはや安全ではありません。認証情報リクエストではテナントIDのみを返します。これをサブドメインとして使用したり、ドメイン名と組み合わせて、ユーザー名(およびパスワード)のみでアクセスできるテナントURLを提供したりすることはできません。正しいテナントへのアクセスは、認証にテナントIDとユーザー名を使用することによってのみ保証できます。例えば、 <tenant-ID>/<username> と認証情報リクエストによって返却されたパスワードのような形式です。この場合、サブドメインは関係ありません。

リクエストヘッダーは次のようになります。

Authorization: Basic <<Base64 encoded credentials <tenant ID>/<username>:<password> >>

例えば、xyz.je1.thingscloud.ntt.com に追加されたデバイスの認証情報リクエストは、「t123456789」のユーザーID、パスワード、およびテナントIDを返す可能性があります。テナントID「t123456789」は、ユーザーIDとパスワードを使用したリクエストのサブドメイン(t123456789.je1.thingscloud.ntt.com )として使用できません。「http403」が返されます。テナントIDは、パスワードとともに「t123456789/<userid>」の形式のユーザーIDとともに使用する必要があります。この場合、実際のサブドメインは無関係です。 t123456789.je1.thingscloud.ntt.com または management.je1.thingscloud.ntt.com、あるいは anything.je1.thingscloud.ntt.com も使用できます。

Things Cloudは、ユーザーIDで指定されたテナントIDを使用して、完全な認証と正しいテナントへのリクエストのルーティングを行います。

有効なテナントURLがわかっている場合(上記の例の xyz.je1.thingscloud.ntt.com )、認証にユーザー名の前に<tenantID>/を付ける必要はありません。

ステップ 1: デバイスが登録済みかどうかを確認する

デバイスの固有IDは、デバイスをインベントリに登録するためにも使用されます。登録はIdentity APIを用いて行います。ID APIでは、各マネージドオブジェクトをタイプで識別される複数の識別子に関連付けることができます。例えば、ハードウェアシリアル番号の場合は「c8y_Serial」、MACアドレスの場合は「c8y_MAC」、IMEIの場合は「c8y_IMEI」となります。

デバイスがすでに登録されているかどうかを確認するには、デバイス識別子とそのタイプを使用して、Identity APIのGETリクエストを使用します。次の例では、ハードウェアシリアル番号「0000000017b769d5」のRaspberry Piをチェックしています。

GET /identity/externalIds/c8y_Serial/raspi-0000000017b769d5 HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.externalid+json; charset=UTF-8; ver=0.9
...
{
    "externalId": "raspi-0000000017b769d5",
    "managedObject": {
        "id": "2480300",
        "self": "https://.../managedObjects/2480300"
    },
    "self": "https://.../identity/externalIds/c8y_Serial/raspi-0000000017b769d5",
    "type": "c8y_Serial"
}

MACアドレスはグローバルで固有であることが保証されていますが、ハードウェアのシリアル番号は異なるハードウェア間で重複する可能性があることに注意してください。したがって、上記の例では、デバイス登録時、シリアル番号の前に「raspiー」を付けています(ステップ3参照)。

ここでは、デバイスはすでに登録されており、ステータスコード200が返されます。レスポンスでは、インベントリのデバイスへのURLが「managedObject.self」に返されます。このURLは、後でデバイスを操作するために使用することができます。

デバイスがまだ登録されていない場合は、ステータスコード404とエラーメッセージが返されます。

GET /identity/externalIds/c8y_Serial/raspi-0000000017b769d6 HTTP/1.1

HTTP/1.1 404 Not Found
Content-Type: application/vnd.com.nsn.cumulocity.error+json;charset=UTF-8;ver=0.9
...
{
    "error": "identity/Not Found",
    "info": "https://www.cumulocity.com/guides/reference/#error_reporting",
    "message": "External id not found; external id = ID [type=c8y_Serial, value=raspi-0000000017b769d6]"
}

ステップ 2: インベントリにデバイスを作成する

上記のステップ1でデバイスを表すマネージドオブジェクトが存在しなかった場合、Things Cloud上にマネージドオブジェクトが作成されます。 マネージドオブジェクトは、デバイスとそのインスタンスとメタデータの両方を記述します。 インスタンスデータには、ハードウェアおよびソフトウェアの情報、シリアル番号、デバイス構成データが含まれます。 メタデータには、サポートされているオペレーションを含むデバイスの機能が記述されています。

マネージドオブジェクトを作成するには、インベントリAPIのマネージドオブジェクトコレクションに対してPOSTリクエストを出します。 次の例では、Linuxエージェントを使用してRaspberry Piを作成しています。

POST /inventory/managedObjects HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json
Accept: application/vnd.com.nsn.cumulocity.managedobject+json
...
{
    "name": "RaspPi BCM2708 0000000017b769d5",
    "type": "c8y_Linux",
    "c8y_IsDevice": {},
    "com_cumulocity_model_Agent": {},
    "c8y_SupportedOperations": [ "c8y_Restart", "c8y_Configuration", "c8y_Software", "c8y_Firmware" ],
    "c8y_Hardware": {
        "revision": "000e",
        "model": "RaspPi BCM2708",
        "serialNumber": "0000000017b769d5"
    },
    "c8y_Configuration": {
        "config": "#Fri Aug 30 09:13:56 BST 2013\nc8y.log.eventLevel=INFO\n..."
    },
    "c8y_Mobile": {
         "imei": "861145013087177",
        "cellId": "4904-A496",
        "iccid": "89490200000876620613"
    },
    "c8y_Firmware": {
        "name": "raspberrypi-bootloader",
        "version": "1.20130207-1"
    },
    "c8y_Software": {
        "pi-driver": "pi-driver-3.4.5.jar",
        "pi4j-gpio-extension": "pi4j-gpio-extension-0.0.5.jar",
        ...
    }
}

HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json;charset=UTF-8;ver=0.9
...
{
    "id": "2480300",
    "lastUpdated": "2013-08-30T10:12:24.378+02:00",
    "name": "RaspPi BCM2708 0000000017b769d5",
    "owner": "admin",
    "self": "https://.../inventory/managedObjects/2480300",
    "type": "c8y_Linux",
    "c8y_IsDevice": {},
    ...
    "assetParents": {
        "references": [],
        "self": "https://.../inventory/managedObjects/2480300/assetParents"
    },
    "childAssets": {
        "references": [],
        "self": "https://.../inventory/managedObjects/2480300/childAssets"
    },
    "childDevices": {
        "references": [],
        "self": "https://.../inventory/managedObjects/2480300/childDevices"
    },
    "deviceParents": {
        "references": [],
        "self": "https://.../inventory/managedObjects/2480300/deviceParents"
    }
}

上記の例では、デバイスの多数のメタデータ項目が含まれています。

詳細は「リファレンスガイド」の デバイス管理ライブラリ をご覧ください。

デバイスが正常に作成された場合は、ステータスコード201が返されます。 例にあるように、元のリクエストに「Accept」ヘッダーが含まれる場合、今後のリクエストでオブジェクトを参照するためのIDとURLを含む、作成されたオブジェクト全体が返されます。 返されるオブジェクトには、子デバイスのコレクションへのリファレンスと、子をデバイスに追加するために使用できる子アセットも含まれます(下記参照)。

ステップ 3: デバイスを登録する

新しいデバイスを作成後、ステップ1で説明したように、そのデバイスを組み込み識別子と関連付けることができます。これにより、デバイスは次回の電源投入後にThings Cloudで検出できるようになります。

上記の例に続き、新しく作成したデバイス「2480300」をそのハードウェアのシリアル番号に関連付けます。

POST /identity/globalIds/2480300/externalIds HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.externalid+json
Accept: application/vnd.com.nsn.cumulocity.externalid+json
...
{
    "type" : "c8y_Serial",
    "externalId" : "raspi-0000000017b769d5"
}

HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.externalid+json;charset=UTF-8;ver=0.9
...
{
    "externalId": "raspi-0000000017b769d5",
    "managedObject": {
        "id": "2480300",
        "self": "https://.../inventory/managedObjects/2480300"
    },
    "self": "https://.../identity/externalIds/c8y_Serial/raspi-0000000017b769d5",
    "type": "c8y_Serial"
}

ステップ 4: インベントリのデバイスを更新する

ステップ1で、デバイスが以前に登録されていると返された場合、インベントリのデバイスの表記が最新であるかを確認する必要があります。 そのために、PUTリクエストがインベントリのデバイスのURLへ送信されます。 変更可能なフラグメントのみが転送されることに注意してください(フラグメントの詳細については、「Things Cloud コンセプトガイド」のThings Cloudのドメインモデルをご覧ください)。

例えば、デバイスのハードウェア情報は通常変更されませんが、ソフトウェアのインストールが変更されている可能性があります。 したがって、デバイスの再起動後に、インベントリのソフトウェア情報を最新の状態にする必要があリます。

PUT /inventory/managedObjects/2480300 HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json
...
{
    "c8y_Software": {
        "pi-driver": "pi-driver-3.4.6.jar",
        "pi4j-gpio-extension": "pi4j-gpio-extension-0.0.5.jar"
    }
}

HTTP/1.1 200 OK
備考
エージェントからデバイス名を更新しないよう注意してください! エージェントは、インベントリで識別できるようにデバイスのデフォルト名を作成しますが、ユーザーがアセット管理の情報より、この名前の編集や更新ができるようにするべきです。

ステップ 5: 子デバイスを検出し、インベントリでそれらを作成または更新する

センサーネットワークの複雑さに応じて、デバイスは、関連する子デバイスを有することができます。家庭のさまざまな部屋にさまざまなセンサーやコントロールを設置するホームオートメーションゲートウェイなどがその良い例です。子デバイスの基本登録方法は、子デバイスが通常エージェントインスタンスを実行しないというところまでは、メインデバイスの登録と同じです(したがって、「com_cumulocity_model_Agent」フラグメントは省略されます)。 デバイスを子にリンクするには、オブジェクトの作成時に返された子デバイスのURLへ、POSTリクエストを送信します(上記参照)。

例えば、下記URLを持つ子デバイスが作成されたとします。
“https://…/inventory/managedObjects/2543801"
このデバイスを親デバイスとリンクするには、次のコマンドを発行します。

POST /inventory/managedObjects/2480300/childDevices HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.managedobjectreference+json
{
    "managedObject" : { 
        "id" : "2543801" 
    }
}

HTTP/1.1 201 Created

最後に、URLにDELETEリクエストを発行することによって、デバイスと参照を削除することができます。例えば、作成したばかりの親デバイスから子デバイスへの参照を削除するには、次のコマンドを発行します。

DELETE /inventory/managedObjects/2480300/childDevices/2543801 HTTP/1.1

HTTP/1.1 204 No Content

この場合、インベントリのデバイス自体は削除されず、参照のみが削除されます。デバイスを削除するには、次のコマンドを発行します。

DELETE /inventory/managedObjects/2543801 HTTP/1.1

HTTP/1.1 204 No Content

このリクエストは、登録情報、メジャーメント、アラーム、イベント、オペレーションなど、デバイスに関連するすべてのデータを削除します。 通常、デバイスを自動的に削除することはお勧めできません。例えば、デバイスの接続が一時的に失われただけの場合、通常そのデバイスに関連するすべての履歴情報を失いたくないでしょう。

オペレーションの操作

Things Cloudの各オペレーションは、実行フローを通じて循環されます。Things Cloudアプリケーションを介してオペレーションが作成されると、PENDING状態になります(つまり、実行のためにキューに入れられてはいても、まだ実行されていない状態です)。エージェントがオペレーションを選択して実行を開始すると、そのオペレーションにはThings Cloudで「EXECUTING」というマークが付けられます。その後、エージェントは、デバイスまたはその子デバイスに対してオペレーションを実行します(例えば、デバイスを再起動したり、リレーを設定したりします)。その後、デバイスまたはその子デバイスの新しい状態を反映してインベントリを更新するでしょう (例:インベントリのリレーの現在の状態を更新します)。次に、エージェントはThings Cloud内のオペレーションを「SUCCESSFUL」または「FAILED」のいずれかとしてマークし、場合によってはエラーを表示します。

Operation status diagram

この実行フローの利点は、オフラインで一時的に通信範囲外にあるデバイスにも対応できることです。 また、ファームウェアのアップグレードなど、再起動が必要なオペレーションをデバイスが対応できるようになります。再起動後、デバイスは以前に実行した内容を知る必要があるため、すべての「EXECUTING」オペレーションを照会して成功したかどうかを確認する必要があります。また、キューに入れられた新しいオペレーションをリッスンする必要があります。

ステップ 6: オペレーションを完了し、サブスクライブする

まだステータスが「EXECUTING」であるオペレーションをクリーンナップするには、エージェントIDおよび状況別にオペレーションを照会します。 下記の例では、リクエストは次のようになります。

GET /devicecontrol/operations?agentId=2480300&status=EXECUTING HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.operationcollection+json;charset=UTF-8;ver=0.9
...
{
    "next": "https://.../devicecontrol/operations?agentId=2480300&status=EXECUTING",
    "operations": [
        {
            "creationTime": "2013-08-29T19:49:15.239+02:00",
            "deviceId": "2480300",
            "id": "2593101",
            "self": "https://.../devicecontrol/operations/2480300",
            "status": "EXECUTING",
            "c8y_Restart": {
            }
        }
    ],
    "statistics": {
        "currentPage": 1,
        "pageSize": 2000
    },
    "self": "https://.../devicecontrol/operations?agentId=2480300&status=EXECUTING"
}

再起動はうまくいったようです – もとに戻りました。オペレーションを「SUCCESSFUL」に設定します。

PUT /devicecontrol/operations/2593101 HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.operation+json
{
    "status": "SUCCESSFUL"
}

HTTP/1.1 200 OK

次に、Things Cloudで作成された新しいオペレーションをリッスンします。 このメカニズムは、Things Cloud OpenAPI仕様のリアルタイム通知 APIで記述されており、標準Bayeuxプロトコルに基づいています。 まず、ハンドシェイクが必要です。 ハンドシェイクは、エージェントが通知用として対応しているプロトコルをThings Cloudに伝え、クライアントIDをエージェントに割り当てます。

POST /devicecontrol/notifications HTTP/1.1
Content-Type: application/json
...
[ {
    "id": "1",
    "supportedConnectionTypes": ["long-polling"],
    "channel": "/meta/handshake",
    "version": "1.0"
} ]

HTTP/1.1 200 OK
...
[ {
    "id": "1",
    "supportedConnectionTypes": ["websocket","long-polling"],
    "channel": "/meta/handshake",
    "version": "1.0",
    "clientId": "139jhm07u1dlry92fdl63rmq2c",
    "minimumVersion": "1.0",
    "successful": true
}]

その後、それぞれのデバイスのエージェントはオペレーションを実行する為の通知にサブスクライブする必要があります。 これは、デバイスのIDをサブスクリプションのチャネルとして使用するPOSTリクエストで行います。 次の例では、Raspberry Piがエージェントを実行し、IDは2480300です:

POST /devicecontrol/notifications HTTP/1.1
Content-Type: application/json
...
[ {
    "id": "2",
    "channel": "/meta/subscribe",
    "subscription": "/2480300",
    "clientId":"139jhm07u1dlry92fdl63rmq2c"
}]

HTTP/1.1 200 OK
...
[ {
    "id":"2",
    "channel": "/meta/subscribe",
    "subscription": "/2480300",
    "successful": true
} ]

最後に、デバイスは接続され、オペレーションが送信されるのを待ちます。

POST /devicecontrol/notifications HTTP/1.1
Content-Type: application/json
...
[ {
    "id": "3",
    "connectionType": "long-polling",
    "channel": "/meta/connect",
    "clientId": "139jhm07u1dlry92fdl63rmq2c"
} ]

このリクエストは、オペレーションが通るまで保留されます。つまり、HTTPサーバーがすぐに応答できずとも、デバイスのオペレーションが行われるまで待機します(ロングポーリング)。

新しいオペレーションをサブスクライブするとき、「PENDING」のオペレーションがある可能性に注意してください。これらをすべて照会する必要があります。クエリとサブスクリプションの間のオペレーションが失われないよう、これらはサブスクリプション後に実行されます。この技術的な処理は、前述の「EXECUTING」オペレーションと同じですが、代わりに「PENDING」を使用します。

GET /devicecontrol/operations?agentId=2480300&status=PENDING HTTP/1.1

サイクルフェーズ

ステップ 7: オペレーションを実行する

まず、エージェントのオペレーションがキューに入れられていると仮定します。これにより、上記のロングポーリングのリクエストがオペレーションで返されます。下記は、単一の構成オペレーションでのレスポンスの一例です。

HTTP/1.1 200 OK
...
[
    {
        "id": "139",
        "data": {
            "creationTime":"2013-09-04T10:53:35.128+02:00",
            "deviceId": "2480300",
            "id": "2546600",
            "self": "https://.../devicecontrol/operations/2546600",
            "status": "PENDING",
            "description": "Configuration update",
            "c8y_Configuration": { "config": "#Wed Sep 04 10:54:06 CEST 2013\n..." }
        },
        "channel": "/2480300"
    }, {
        "id": "3",
        "successful": true,
        "channel": "/meta/connect"
    }
]

エージェントがオペレーションを取得すると、Things Cloud上ではPUTリクエストを使用して「EXECUTING」状態になります(上記の「FAILED」の例を参照)。 デバイスでオペレーションを実行し、Things Cloudインベントリで必要な更新を実行します。最後に、結果に応じてオペレーションは「SUCCESSFUL」または「FAILED」に設定されます。 そして、上記のように 「/devicecontrol/notifications」 に再接続し、次のオペレーションを待ちます。

備考
キューに入れられたオペレーションが失われないように、デバイスは10秒以内にサーバーに再接続する必要があります。 これは、Things Cloudがリアルタイムのデータをバッファーする時間です。 間隔はハンドシェイク時に指定できます。

ステップ 8: インベントリを更新する

通常、デバイスのインベントリ内容は最新の状態を表すので、継続的な更新の対象になります。 例として、GPSチップを搭載したデバイスを考えてみましょう。このデバイスは、インベントリの現在地を最新の状態に保ちます。 同時に、位置の更新とイベントを報告して、位置の追跡を維持します。技術的にこのような更新は、ステップ4と同じリクエストで報告されます。

ステップ 9: メジャーメントを送信する

Things Cloudで新しいメジャーメントを作成するには、メジャーメントとともにPOSTリクエストを発行します。 下記は、信号強度のメジャーメントを作成する例になります。

POST /measurement/measurements HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.measurement+json
...
{
    "source": { "id": "2480300" },
    "time": "2013-07-02T16:32:30.152+02:00",
    "type": "huawei_E3131SignalStrength",
    "c8y_SignalStrength": {
        "rssi": { "value": -53, "unit": "dBm" },
        "ber": { "value": 0.14, "unit": "%" }
    }
}

HTTP/1.1 201 Created

ステップ 10: イベントを送信する

同様に、イベントにもPOSTリクエストを使用します。 次の例は、GPSセンサーからの位置の更新を示しています。

POST /event/events HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.event+json
...
{
    "source": { "id": "1197500" },
    "text": "Location updated",
    "time": "2013-07-19T09:07:22.598+02:00",
    "type": "queclink_GV200LocationUpdate",
    "c8y_Position": {
        "alt": 73.9,
        "lng": 6.151782,
        "lat": 51.211971
    }
}

HTTP/1.1 201 Created

Things Cloudのすべてのデータタイプには、追加でフラグメントという形の任意の拡張を含むことができます。上記では、イベントに位置情報が含まれていますが、自己定義のフラグメントを追加することも可能です。

ステップ 11: アラームを送信する

アラームとは、解決するために人の介入を必要とするイベントを表します。例えば、デバイスのバッテリーが切れた場合、誰かがデバイスのバッテリーを交換する必要があります。 アラームの作成は、技術的にはイベントの作成と非常によく似ています。

POST /alarm/alarms HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.alarm+json
Accept: application/vnd.com.nsn.cumulocity.alarm+json
...
{
    "source": { "id": "10400" },
    "text": "Tracker lost power",
    "time": "2013-08-19T21:31:22.740+02:00",
    "type": "c8y_PowerAlarm",
    "status": "ACTIVE",
    "severity": "MAJOR",
}

HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.alarm+json
...
{
    "id": "214600",
    "self": "https://.../alarm/alarms/214600",
    ...
}

ただし、同じようなアラームがシステム内ですでに有効になっている場合は、デバイスのアラームを作成しない方がよいでしょう。多数のアラームを作成すると、ユーザーインターフェースがいっぱいになり、すべてのアラームを手動でクリアする必要が生じる場合があります。上の例は、Raspberry Piのアクティブアラームを見つけるためのものです。

GET /alarm/alarms?source=2480300&status=ACTIVE HTTP/1.1

イベントとは異なり、アラームは更新ができます。 問題が解決した場合(例:バッテリーが交換され、電源が復旧した場合)、対応するアラームが自動的にクリアされ、手動での作業が不要になります。これは、アラームのURLへのPUT要求によって実行できます。 上記のアラーム作成の例では、「Accept」ヘッダーを使用して、レスポンス内の新しいアラームのURLを取得しました。このURLを使用してアラームをクリアできます。

PUT /alarm/alarms/214600 HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.alarm+json
...
{
    "status": "CLEARED"
}

HTTP/1.1 200 OK

イベントの送信、あるいはアラームの発生のどちらを選ぶか判断ができない場合は、とりあえずイベントを発生させて、ユーザー自身にCEP ルール より、イベントをアラームへ変換するかどうか決定させるとよいでしょう。

物理デバイスの交換

すでにThings Cloudプラットフォームに接続されている物理デバイスを、その外部 ID とデバイスが収集したデータを維持したまま交換できます。 下記を実行します。

  1. 古い物理デバイスの電源を切ります。
  2. 通常のデバイスと同様に、新しいデバイスを登録と起動します。
  3. デバイスが新しいマネージドオブジェクトを作成した後、新しい物理デバイスの電源をオフにします。
  4. Things Cloudのデバイス管理 で新しいデバイスオブジェクトを開き、デバイスの所有者とデバイスの外部 ID を検索します。
  5. デバイスから外部 ID を削除します。
  6. Things Cloudのデバイス管理で古いデバイスを開き、その所有者を調べたものに変更し、新しいデバイスから削除した外部 ID も追加します。
  7. 以前に作成した新しいデバイスオブジェクトを削除し、デバイスユーザーは保持します。
  8. 新しい物理デバイスの電源を入れます。

新しい物理デバイスは、データを既存のマネージドオブジェクトに送信します。

注意
上記の手順は、デバイスが標準のデバイスブートストラップを使用している場合にのみ機能します。 それ以外の場合は、デバイス インテグレーターまたはメーカーにお問い合わせください。
備考
デバイスに子デバイスがある場合は、その所有者も更新する必要があります。