アプリケーションの開発

本セクションでは、アプリケーション開発向けに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
...

デバイス(アセット)が正常に作成された場合は、ステータスコード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
{

ここで建物を再度取得すると、部屋が建物の子として登録されていることが分かります。

GET /inventory/managedObjects/2549800

応答:

HTTP/1.1 200 OK
Content-Type: application/vnd.com.nsn.cumulocity.managedObject+json; charset=UTF-8; ver=0.9
...

デバイスとアセットのリンク

アセットを他の子アセットにリンクするのと同様に、アセットをモニタリングおよび制御するデバイスにリンクすることもできます。たとえば、部屋に光センサーが設置されており、その光センサーの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システムに格納されているアセットの同期の手順は、デバイスの登録手順とまったく同じです。

特定の機能の問い合わせ

アプリケーションを特定のタイプのデバイスの仕様から切り離すために、アプリケーションはフラグメントを使用してインベントリに問い合わせることができます(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
...

たとえば、プロパティのc8y_Position を使用して、マップ上にオブジェクトを配置することができます。標準フラグメントは、デバイス管理ライブラリセンサー・ライブラリで定義されています。

/platform リソースに問い合わせると、さらにどのようなデータを問い合わせることができるかがわかります(デバイスSDKガイドの RESTを使用したデバイス統合をご覧ください)。

クエリは必ずしもすべての結果を一度に返すわけではなく、1ページ分の結果のみを返すことに注意してください。ページングの詳細については、RESTの実装>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
...

オペレーションをデバイスへ送信

デバイスのオペレーションをトリガーするには、オペレーションをデバイスコントロール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
...

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クライアントでこれらを受け取りたい場合、リアルタイム通知APIを使ってそれらにチャネル接続できるようにします。このAPIは、HTTPSロングポーリングを使用したBayeuxプロトコルに基づいています。適用される制限については、リアルタイム通知をご覧ください。まず、ハンドシェイクが必要です。ハンドシェイクは、クライアントが通知のためにサポートするプロトコルを 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要求を使用して行われます。次の例では、モジュール名に「myRule」を使用し、selectステートメント("@Name('')")に名前を付与していませんので、接続チャネルは「/myRule/*」になります。

POST /cep/notifications
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
...

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

HTTP/1.1 200 OK
...
[
    {
        "id": "139",
        "data": {
            "creationTime": "...",
            "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": "...",
            "type": "c8y_LocationUpdate",
            "c8y_Position": {
                "alt": 58.34,
                "lng": 6.769717,
                "lat": 51.267259
            },
            "channel": "/myRule/*"
        },
        "id": "3",
        "successful": true,
        "channel": "/meta/connect"
    }
]