アプリケーション開発

概要

本セクションでは、アプリケーション開発向けにThings Cloud REST APIを使用する場合の基本的ユースケースを簡単に説明します。

アセットを登録する

アセットとは、あなたのビジネスおよびアプリケーションにおいて注目する対象を指します。例えば、主にビル管理またはホームオートメーションのビジネスを展開する場合、建物や部屋がアセットになるでしょう。あるいは、機器のメンテナンスを手掛ける場合は経路や機器がアセットになるでしょう。

アセットはデバイスと併せてインベントリに保存されますが、多くの場合、デバイスに無関係な固有の構造を有します。貴方はアセットを、インベントリ内のマネージドオブジェクトのコレクションにPOSTすることによって作成します。例えば、インベントリに新たな建物を1つ作成する手順は以下の通りです。

POST /inventory/managedObjects HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.managedObject+json
Accept: application/vnd.com.nsn.cumulocity.managedObject+json
...
{
    "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": "http://.../inventory/managedObjects/2549800",
    "type": "c8y_Building",
    "lastUpdated": "2013-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を含む完全なオブジェクトが返されます。返されるオブジェクトには子デバイスおよび子アセットのコレクションに対する参照も含まれ、これを使用してデバイスに子デバイスを追加することができます。

例えば、部屋を1室作成済みで、その部屋「自体」のプロパティが「https://.../inventory/managedObjects/2549700 」であると想定しましょう。この部屋を建物にリンクさせるには、建物の子アセットコレクションにPOSTします(上記の「childAssets」の「self」プロパティをご覧ください)。

POST /inventory/managedObjects/2549800/childAssets HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.managedObjectReference+json

{ "managedObject" : { "self" : "http://.../inventory/managedObjects/2549700" } }

HTTP/1.1 201 Created

ここで、建物を再度取得すると、部屋がすでにこの建物の子アセットとして登録済みであることが分かります。

GET /inventory/managedObjects/2549800 HTTP/1.1

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": "http://.../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 HTTP/1.1
Content-Type: application/vnd.com.nsn.cumulocity.managedObjectReference+json

{ "managedObject" : { "self" : "https://.../inventory/managedObjects/2480500" } }

HTTP/1.1 201 Created

アセットを外部システムと同期させる

多くの場合、Things Cloudが会社のアセットを取り扱う唯一のITシステムとなるわけではありません。外部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

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&currentPage=2",
    "statistics": {
        "currentPage": 1,
        "pageSize": 5,
        "totalPages": 4
    },
    "self": "https://.../inventory/managedObjects?withTotalPages=true&fragmentType=c8y_Position&pageSize=5&currentPage=1"
}

次に、例えばオブジェクトをマップに配置することができます。標準フラグメントがデバイスマネジメントライブラリおよびセンサー・ライブラリで定義されています。

「/platform」に問い合わせると、あなたのデータを問い合わせたい場合のさらなる可能性が分かります(「はじめに」をご覧ください)。

注記:クエリは必ずしもすべてのクエリ結果をいっぺんに返すわけではなく、結果の「ページ」を返すのみです。ページングについて詳しくはクエリ結果のページングをご覧ください。オプションパラメータ「withTotalPages」を使用すると、クエリに完全なページ統計を包含させることができますが、反面、性能がやや低下します。

センサーからの読み取りを問い合わせる

インベントリ同様、特定のセンサー読み取りを問い合わせることもできます。例えば、(このテキスト執筆時点の)前月の光メジャーメントを問い合わせてみましょう。手順は以下の通りです。

GET /measurement/measurements?dateFrom=2013-08-05&dateTo=2013-09-05&fragmentType=c8y_LightMeasurement HTTP/1.1

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 }
            }
        },
        ...
    ]
    ...
}

オペレーションをデバイスに送信する

デバイス上でオペレーションをトリガーするには、オペレーションをDevice Control APIへPOSTします。以下の例では、ID「2480300」のデバイス(以前登録したRaspberry Pi)を再起動しています。

POST /devicecontrol/operations HTTP/1.1
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
...
{
    "creationTime": "2013-09-05T19:18:16.117+02:00",
    "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データストアへの問い合わせに加え、「Things Cloudにおけるリアルタイム処理」に記載の通り、イベントをリアルタイムで処理/受信することもできます。例えば、リアルタイムの位置更新情報をマップに表示させたいと想定しましょう。以下の通り、「アドミニストレーション」アプリケーション(またはREST API)を使用して、新規のルールモジュール「myRule」を作成します。

select *
from EventCreated e
where e.event.type = "c8y_LocationUpdate";

位置更新情報を送信するデバイスをお持ちの場合、それらがユーザーインタフェースに即座に表示されるはずです。それらをあなたの固有RESTクライアントで受信したい場合、Notification APIを使用してチャネル接続できるようにします。このAPIはBayeuxプロトコルがベースです。まず、ハンドシェイクが必要です。ハンドシェイクとは、クライアントが通知向けにサポートするプロトコルをThings Cloudに伝達し、クライアントにクライアントIDを割り当てる機能です。

POST /cep/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": ["websocker","long-polling"],
    "channel": "/meta/handshake",
    "version": "1.0",
    "clientId": "71fjkmy0495rxrkfcmp0mhcev1",
    "minimumVersion": "1.0",
    "successful": true
}]

ハンドシェイクの後、クライアントは上記のルールの出力にチャネル接続する必要があります。これは接続チャネルに該当するモジュール名およびステートメント名と併せてPOSTリクエストを使用して行われます。当方の例では「myRule」というモジュール名を使用し、「select」ステートメント("@Name('')")に名前を付与していませんので、接続チャネルは「/myRule/*」です。

POST /cep/notifications HTTP/1.1
Content-Type: application/json
...
[ {
    "id": "2",
    "channel": "/meta/subscribe",
    "subscription": "/myRule/*",
    "clientId":"71fjkmy0495rxrkfcmp0mhcev1"
}]

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

最後に、クライアントは接続状態のまま、送られてくるイベントを待ちます。

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

このリクエストは、モジュールイベントが発生するまでブロックします。一つの位置更新を含む応答例を紹介します。

HTTP/1.1 200 OK
...
[
    {
        "id": "139",
        "data": {
            "creationTime": "2013-08-30T09:38:45.551+02:00",
            "id": "2481400",
            "self": "https://.../event/events/2481400",
            "source": {
                "id": "2480700",
                "name": "RaspPi BCM2708 0000000017b769d5 Gps eM9",
                "self": "https://.../inventory/managedObjects/2480700"
            },
            "text": "Location updated",
            "time": "2013-08-29T21:20:01.671+02:00",
            "type": "c8y_LocationUpdate",
            "c8y_Position": {
                "alt": 58.34,
                "lng": 6.769717,
                "lat": 51.267259
            },
            "channel": "/myRule/*"
    }, {
        "id": "3",
        "successful": true,
        "channel": "/meta/connect"
    }
]