概要
Things Cloudでは、すべての外部通信にRESTを採用しています。 通信の発信元がIoTデバイス、Webアプリケーション、またはバックオフィスITシステムであるかに関わらず、通信プロトコルは常にRESTです。
RESTはHTTP(S) とTCPをベースにした非常にシンプルでセキュアなプロトコルです。現在、非常にシンプルなデバイスから大規模なITに至るまで、すべてのネットワーク型プログラミング環境でサポートされている事実上のインターネット標準となっています。RESTを紹介している多くの本の中の1つにRESTful Web Servicesがあります。
ここでの説明は、各インターフェースの詳細が記載されたThings Cloud OpenAPI仕様と密接に関連しています。 Things Cloud OpenAPI仕様内の関連するセクションは、次の通りです。
- REST実装:すべての一般的な概念のリファレンス
- デバイス管理ライブラリ:デバイス管理のデータモデルの具体的な説明
- センサー・ライブラリ:センサーとコントロールのデータモデルの具体的な説明
JavaまたはC#を使用してアプリケーションを開発する場合は、Things Cloudの機能にさらに簡単にアクセスできるよう、このガイドの関連するセクションもご覧ください。 RESTインターフェース全般、およびRESTによるデバイス統合の詳細については、デバイス統合ガイドの REST セクション をご覧ください。
RESTインターフェースの使用法
現在、ほとんどのプログラミング環境において、RESTベース通信への対応は際立っています。Things CloudのRESTインターフェースを理解し、使用するにあたり、利用できる膨大なコマンドラインツールやブラウザ拡張機能が役立ちます。
例えば、多数のオペレーティングシステムに「curl」コマンドがあらかじめインストールされています。Things Cloud APIのブラウジングを開始したい場合、以下のコマンドラインが基本となります。
$ curl -u <username>:<password> https://<yourTenant>.je1.thingscloud.ntt.com/platform
<username>
と <password>
を、自分がThings Cloudに登録する際に使用するユーザー名とパスワードに書き換えます。同様に、<yourTenant>
を、テナント名に書き換えます。
このコマンドはThings Cloudのあらゆる基本インターフェースにリンクを返します。
...
"inventory": {
"managedObjects": {
"references": [],
"self": "https://<yourURL>/inventory/managedObjects"
},
"managedObjectsForFragmentType": "https://<yourURL>/inventory/managedObjects?fragmentType={fragmentType}",
"managedObjectsForListOfIds": "https://<yourURL>/inventory/managedObjects?ids={ids}",
"managedObjectsForType": "https://<yourURL>/inventory/managedObjects?type={type}",
"self": "https://<yourURL>/inventory"
},
...
出力形式をもっと整えたい場合、curl … | python -mjson.tool
を試してみてください。
$ curl -u <username>:<password> https://<yourTenant>.je1.thingscloud.ntt.com/platform | python -m json.tool
この時点より、返されるさまざまなオブジェクトへ移動することができます。例えば、managedObjectsエンドポイントに従って、インベントリ内の項目を取得できます。
$ curl -u <username>:<password> https://<yourTenant>.je1.thingscloud.ntt.com/inventory/managedObjects
インベントリ内の項目のサブセットが実際に返されることが分かります。これが所謂「ページ」です。ページについての詳細はThings Cloud OpenAPI仕様のRESTの用法 > クエリ結果のページングをご覧ください。
Postmanの使用
RESTインターフェースやThings Cloudデータベースのコンテンツを探索する場合、PostmanのようなグラフィカルRESTクライアントが便利です。
Software AG 社から多くの API コマンドのサンプルが提供されています。利用する場合、Postman をダウンロードしてインストール してください。Postman を開始した後、create an account または、Take me straight to the app を選べます。
では、最上段のタブにある Collections をクリックしてください。Things Cloud API というフォルダがサンプルと共に表示されているはずです。そのフォルダとサブフォルダ Alarms を開き、Get collection of alarms をクリックしてください。これで Things Cloud からどのようにアラームを取得するかの例が示されます。
例にはプレースホルダーが含まれていることに注意してください。この例では、 {{url}}/alarm/alarms の {{url}} がプレースホルダーです。 Postmanにこれらのプレースホルダーの埋め方と、Things Cloudのアカウントへの接続方法を指定する必要があります。そのためには、environment を作成し、プレースホルダーを設定してください。
- 右上の歯車をクリックし、Manage Environments を選び、Add をクリックしてください。
- environment の名前(例えばテナント名)を入力して、プレースホルダーの値を追加してください。
- キー url の値を https://<TENANT_NAME>.je1.thingscloud.ntt.com に設定し、Submitをクリックしてください。
- キー auth の値をREST要求のAuthorizationヘッダーの値に設定してください。
- Add をクリックし、ダイアログボックスを閉じてください。初期値では「No environment」と表示されていた右上のドロップダウンボックスから新しく作成したenvironmentを選択します。
例えば、テナント ID がt07007007
、ユーザー名がWinter
、パスワードがjh0nS0nw
であるとします。auth
キーの正しい値を判断する簡単な方法は、次のように Base64 コマンドを使用することです。
$ echo -n t07007007/winter:jh0nS0nw | base64
結果のテキストは「dDA3MDA3MDA3L3dpbnRlcjpqaDBuUzBudw==」であり、auth
キーの値としてBasic dDA3MDA3MDA3L3dpbnRlcjpqaDBuUzBudw==
を使用する必要があります。 オンラインの Base64 エンコード/デコード ツールを使用しても、同じ結果を得ることができます。
色々なAPI を使ってみましょう。
アプリケーションの開発
本セクションでは、アプリケーション開発向けにThings Cloud REST APIを使用する場合の基本的なユースケースを簡単に説明します。
基本ユースケース
アセットの登録
アセットとは、あなたのビジネスとアプリケーションが対象としているオブジェクトのことです。例えば、主にビル管理またはホームオートメーションのビジネスを展開する場合、アセットはビルや部屋になります。または、機器の修理に関するビジネスであれば、アセットは経路や機器となるでしょう。
アセットはデバイスとともにインベントリに保存されますが、多くの場合、デバイスに依存しない独自の構造を持っています。アセットを作成するには、インベントリ内のマネージドオブジェクトのコレクションにPOSTし作成します。例えば、インベントリに新たな建物を作成するには、次のように入力します。
POST /inventory/managedObjects
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json
Accept: application/vnd.com.nsn.cumulocity.managedobject+json
Authorization: Basic ...
{
"name": "Building 043",
"type": "c8y_Building"
}
レスポンス:
HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json;charset=UTF-8;ver=0.9
...
{
"owner": "admin",
"id": "2549800",
"self": "https://.../inventory/managedObjects/2549800",
"type": "c8y_Building",
"lastUpdated": "2018-09-05T16:38:31.250+02:00",
"name": "Building 043",
"assetParents": {
"references": [],
"self": "https://.../inventory/managedObjects/2549800/assetParents"
},
"childAssets": {
"references": [],
"self": "https://.../inventory/managedObjects/2549800/childAssets"
},
"childDevices": {
"references": [],
"self": "https://.../inventory/managedObjects/2549800/childDevices"
},
"deviceParents": {
"references": [],
"self": "https://.../inventory/managedObjects/2549800/deviceParents"
}
}
デバイス(アセット)が正常に作成された場合は、ステータスコード201が返されます。上記の例のように、元のリクエストに「Accept」ヘッダーが含まれている場合は、今後のリクエストでオブジェクトを参照するためのIDとURLを含む、完全なオブジェクトが返却されます。返されるオブジェクトには、デバイスに子を追加するために使用できる子デバイスおよび子アセットへの参照も含まれます。
例えば、部屋も作成し、その部屋の「self」プロパティが「https://…/inventory/managedObjects/2549700」である場合、部屋を建物にリンクするには、建物の子アセットコレクション(上記の「childAssets」の「self」プロパティ参照)にPOSTします。
POST /inventory/managedObjects/2549800/childAssets HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.managedobjectreference+json
{
"managedObject" : {
"self" : "https://.../inventory/managedObjects/2549700"
}
}
ここで建物を再度取得すると、部屋が建物の子として登録されていることが分かります。
GET /inventory/managedObjects/2549800
レスポンス:
HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.managedobject+json; charset=UTF-8; ver=0.9
...
{
"owner": "admin",
"id": "2549800",
"self": "https://.../inventory/managedObjects/2549800",
...
"childAssets": {
"references": [
{
"managedObject": {
"id": "2549700",
"name": "Room 042",
"self": "https://.../inventory/managedObjects/2549700"
},
"self": "https://.../inventory/managedObjects/2549800/childAssets/2549700"
}
],
"self": "https://.../inventory/managedObjects/2549800/childAssets"
}
}
デバイスとアセットのリンク
アセットを他の子アセットにリンクするのと同様に、アセットをモニタリングおよび制御するデバイスにリンクすることもできます。例えば、部屋に光センサーが設置されており、その光センサーのURLが「https://…/inventory/managedObjects/2480500」であるとします。次のように、部屋のchildDevicesにPOSTします。
POST /inventory/managedObjects/2549700/childDevices
Content-Type: application/vnd.com.nsn.cumulocity.managedobjectreference+json
{
"managedObject" : {
"self" : "https://.../inventory/managedObjects/2480500"
}
}
アセットと外部システムとの同期
多くの場合、企業のアセットを扱うITシステムはThings Cloudだけではありません。外部ITシステムに格納されているアセットの同期の手順は、デバイスの登録手順とまったく同じです。
- Identity APIを使用して、外部ITシステムのアセットIDを Things Cloud のアセットIDにリンクさせます。
- Inventory APIを使用して、外部システムのデータに基づいて Things Cloud のインベントリにアセットを作成または更新します。
特定の機能のクエリ
アプリケーションを特定のタイプのデバイスの仕様から切り離すために、アプリケーションはフラグメントを使用してインベントリに問い合わせることができます(Things Cloud のドメインモデルのフラグメントのセクションをご覧ください)。たとえば、位置情報を持つすべてのマネージドオブジェクトを検索するには、以下を使用します。
GET /inventory/managedObjects?fragmentType=c8y_Position&withTotalPages=true
レスポンス:
HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.managedobjectcollection+json; charset=UTF-8; ver=0.9
...
{
"managedObjects": [{
"id": "2480700",
"lastUpdated": "2013-08-30T10:15:44.218+02:00",
"name": "RaspPi BCM2708 0000000017b769d5 Gps eM9",
"owner": "admin",
"self": "https://.../inventory/managedObjects/2480700",
"type": "c8y_TinkerForge_Gps",
"c8y_Position": {
"alt": 102.36,
"lng": 6.769717,
"lat": 51.267259
},
...
},
...
]
"next": "https://.../inventory/managedObjects?withTotalPages=true&fragmentType=c8y_Position&pageSize=5¤tPage=2",
"statistics": {
"currentPage": 1,
"pageSize": 5,
"totalPages": 4
},
"self": "https://.../inventory/managedObjects?withTotalPages=true&fragmentType=c8y_Position&pageSize=5¤tPage=1"
}
例えば、プロパティのc8y_Position
を使用して、地図上にオブジェクトを配置することができます。標準フラグメントは、デバイス管理ライブラリ と センサー・ライブラリで定義されています。
/platform リソースにクエリすると、さらにどのようなデータをクエリすることができるかがわかります(「デバイス統合ガイド」の RESTデバイスインテグレーションをご覧ください)。
クエリは必ずしもすべての結果を一度に返すわけではなく、1ページ分の結果のみを返すことに注意してください。ページングの詳細については、Things Cloud OpenAPI仕様のREST implementation >
RESTの用法 >クエリ結果のページングをご覧ください。オプションパラメータwithTotalPages
を指定すると、クエリにページ全体の統計情報が含まれますが、パフォーマンスは多少低下します。
センサーデータのクエリ
インベントリと同様に、特定のセンサーデータを取得することもできます。例えば、前月(この文章の執筆時点から)の光センサーメジャーメントを次のようにクエリすることができます。
GET /measurement/measurements?dateFrom=2019-04-01&dateTo=2019-05-31&fragmentType=c8y_LightMeasurement
レスポンス:
HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.measurementcollection+json; charset=UTF-8; ver=0.9
...
{
"measurements": [{
"id": "2480900",
"self": "https://.../measurement/measurements/2480900",
"source": {
"id": "2480500",
"self": "https://.../inventory/managedObjects/2480500"
},
"time": "2013-08-29T21:19:52.321+02:00",
"type": "c8y_LightMeasurement",
"c8y_LightMeasurement": {
"e": {
"unit": "lux",
"value": 169.2
}
}
},
...
]
...
}
オペレーションをデバイスへ送信
デバイスのオペレーションをトリガーするには、オペレーションをデバイス制御APIへPOSTします。次の例では、ID「2480300」のデバイスを再起動します(デバイスSDKガイド内のデバイス統合で統合されているRaspberry Pi)。
POST /devicecontrol/operations
Content-Type: application/vnd.com.nsn.cumulocity.operation+json;
Accept: application/vnd.com.nsn.cumulocity.operation+json;
{
"deviceId": "2480300",
"c8y_Restart":{}
}
レスポンス:
HTTP/1.1 201 Created
Content-Type: application/vnd.com.nsn.cumulocity.operation+json; charset=UTF-8; ver=0.9
...
{
...
"deviceId": "2480300",
"id": "2550200",
"self": "https://.../devicecontrol/operations/2550200",
"status": "PENDING",
"c8y_Restart": {}
}
POSTコマンドは、該当のデバイスに対するオペレーションを作成した後、その作成結果を即座に返します。オペレーションの作成と実行は非同期です。リクエスト例でオプションの「Accept」ヘッダーを追加したので、レスポンスにおいてはself
プロパティにおけるURLを含む、すべての発行済オペレーションを取得することになります。そのURLに対してGETを使用すると、以下の通り、現在のオペレーション実行状態をチェックすることができます。
GET /devicecontrol/operations/2550200 HTTP/1.1
HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.operation+json; charset=UTF-8; ver=0.9
{
"status": "PENDING",
...
}
ここでの「PENDING」ステータスとは、デバイスがまだオペレーションを受け取っていないことを意味します。「EXECUTING」は、デバイスがオペレーションを実行中であることを意味します。最後に、「SUCCESSFUL」または「FAILED」は、オペレーションが完了したことを示します。
イベントの応答を受信する
Things Cloud データストアをクエリするだけでなく、イベントをリアルタイムで処理して受信することもできます。たとえば、リアルタイムの位置情報の更新を地図上に表示したいとします。
位置情報の更新を送信するデバイスをお持ちの場合、ユーザーインターフェースに即座に表示されるはずです。自分のRESTクライアントでこれらを受け取りたい場合、リアルタイム通知APIを使ってそれらにチャネル接続できるようにします。このAPIは、HTTPSロングポーリングを使用したBayeuxプロトコルに基づいています。適用される制限については、リアルタイム通知 APIをご覧ください。まず、ハンドシェイクが必要です。ハンドシェイクは、クライアントが通知のためにサポートするプロトコルを Things Cloud に伝え、クライアントにクライアントIDを割り当てる機能です。
POST /cep/notifications
Content-Type: application/json
...
[ {
"id": "1",
"supportedConnectionTypes": ["long-polling"],
"channel": "/meta/handshake",
"version": "1.0"
} ]
HTTP/1.1 200 OK
...
[ {
"id": "1",
"supportedConnectionTypes": ["long-polling"],
"channel": "/meta/handshake",
"version": "1.0",
"clientId": "71fjkmy0495rxrkfcmp0mhcev1",
"minimumVersion": "1.0",
"successful": true
}]
ハンドシェイク後、クライアントは特定のデバイス チャネルまたはすべてのデバイスチャネル (*) にサブスクライブする必要があります。 これは、チャネル名を指定した POST リクエストを使用して行われます。
たとえば、内部 ID が「24800」のデバイスからイベントに関する通知を受信する場合、サブスクリプション チャネルは「/events/24800」です。
POST /notification/realtime
Content-Type: application/json
...
[ {
"id": "2",
"channel": "/meta/subscribe",
"subscription": "/events/24800",
"clientId": "71fjkmy0495rxrkfcmp0mhcev1"
}]
HTTP/1.1 200 OK
...
[ {
"id":"2",
"channel": "/meta/subscribe",
"subscription": "/events/24800",
"successful": true,
} ]
最後に、クライアントは接続状態のまま、イベントが送られてくるのを待ちます。
POST /notification/realtime HTTP/1.1
Content-Type: application/json
...
[ {
"id": "3",
"connectionType": "long-polling",
"channel": "/meta/connect",
"clientId": "71fjkmy0495rxrkfcmp0mhcev1"
} ]
このリクエストは、モジュールイベントが発生するまでブロックします。1つの位置更新を含むレスポンス例を紹介します。
HTTP/1.1 200 OK
...
[
{
"id": "3",
"data": {
"creationTime": "...",
"id": "2481400",
"self": "https://.../event/events/2481400",
"source": {
"id": "24800",
"name": "RaspPi BCM2708 0000000017b769d5 Gps eM9",
"self": "https://.../inventory/managedObjects/24800"
},
"text": "Location updated",
"time": "...",
"type": "c8y_LocationUpdate",
"c8y_Position": {
"alt": 58.34,
"lng": 6.769717,
"lat": 51.267259
},
"channel": "/events/24800"
},
"id": "3",
"successful": true,
"channel": "/meta/connect"
}
]