SmartRESTの使用

概要

Things Cloud REST APIは、ほとんどの環境から簡単に使用できる汎用IoTプロトコルを提供します。これはどのようなIoTユースケースにもアドホックに適応させることができ、また標準的なインターネット通信およびセキュリティーメカニズムを利用します。適切な標準技術を利用しているため、独自IoTプロトコルと比べ先進的である一方、ローエンドのマイクロコントローラまたは低帯域幅通信チャネルなど、非常に制約の多い環境には課題をもたらすことがあります。

こうした環境向けに、Things Cloud はいわゆる「SmartREST」プロトコルを提供します。SmartRESTは以下のように、標準技術の利点と特別仕様のプロトコルの利点を同時に提供するものです。

  • 標準HTTP技術の使用により、どのようなネットワークでもそのまま機能します。
  • HTTPの認証と暗号化に対応します。
  • プロトコルのバージョニングにも上手く対処します。
  • ネットワークトラフィックの使用量は、通常の操作ではペイロードデータのみを転送し、最適化されたプロトコルのものに近い。
  • CSV(コンマ区切り値)を基本とし、したがってCベース環境から扱いやすい。
  • 時計のないデバイス向けに、サーバーが生成するタイムスタンプに対応します。

次のセクションでは、SmartRESTの背景にある概念と、使用する基本プロトコルについて記述します。SmartRESTは後述する通り、テンプレートと呼ばれる概念の使用により、メタデータをペイロードデータから分離する処理を基本としています。最後に、SmartRESTを使用してデータを送受信する方法を説明します。プロトコル詳細はSmartRESTリファレンスをご覧ください。

SmartRESTの動作方法

下記の画像は、SmartRESTの動作を図示したものです。デバイスおよび他のクライアントは Things Cloud 上の専用SmartRESTエンドポイントに接続し、それぞれのデータをコンマ区切り値からなる行として送信します。これらの行は Things Cloud のSmartRESTプロキシにより、標準の Things Cloud REST APIリクエストへと展開されます。同様に、Things Cloud からの応答は通常のJSON形式からプロキシによってコンマ区切り値に圧縮された後、デバイスに返却されます。

SmartREST architecture

Things Cloud はコンマ区切り値をどうやって、意味のあるRESTリクエストへと解釈するのでしょうか? それを行うために、デバイスはテンプレートを Things Cloud に登録します。テンプレートは、展開されたRESTリクエスト形式をプレースホルダと一緒に保持しており、その中へ Things Cloud の SmartREST プロキシが連続的にコンマ区切り値を挿入します。応答の場合、テンプレートはコンマ区切り値を構築するために、構造化されたREST応答から抽出する値を表現します。

テンプレートは、デバイスのソフトウェアまたはファームウェアのバージョンに関連付けられます。通常、デバイスまたはアプリケーションに固有な実装は、用途に応じたリクエストタイプに対応しており、決まった範囲の要求を発行するでしょう。同じ実装のデバイスはすべて、同じ一連のリクエスト種別を共有します。したがって、テンプレートは実装段階で定義できます。テンプレートを Things Cloud で使用できるようにするため、特定の実装を伴う最初のデバイスがそのテンプレートを送信し、そして同類のデバイスすべてがテンプレートを使用できるようにようにします。

以下はこのプロセスの例示です。「Device_1.0」のバージョンを実装したデバイスがSmartREST経由での通信を開始するという状況を想定します。デバイスは認証情報を取得した後、SmartRESTプロキシに対し、テンプレートが登録済みであるか否か問い合わせます。テンプレートがサーバー上で見つからない場合、デバイスはテンプレートを単一の静的テキストリクエストとして Things Cloud へ送信します。この手順が完了したら、このテンプレートを使用する同類のデバイスはすべて、テンプレートをサーバーに再送しなくても、SmartRESTを使用する通信を開始することができます。

SmartREST templates

この例は、変換プロセス概要も例示しています。「Template 1」において、「%%」はプレースホルダであり、これをSmartRESTプロキシが埋めます。「time」はサーバー側タイムスタンプに置き換えられます(下記参照)。残りのプレースホルダはリクエストデータに置き換えられます。リクエスト例における行「1,200,20.5」は以下のように解釈されます。

  • 最初のカラムは、使用するテンプレート、この例ではTemplate 1を参照します。
  • 「200」はテンプレート内の最初のプレースホルダを指し、この例で言えば「source」要素内のIDを指します。(メジャーメントを送信するデバイスのID)
  • 「20.5」はテンプレート内の2番目のプレースホルダを指し、この例では温度メジャーメントの値に置き換えられます。

基本的なSmartRESTプロトコル

あらゆるSmartRESTリクエストの基本構造は以下の通りです。

  • リクエストはすべて、最終にどう変換されるかによらず、エンドポイント「/s」宛のPOSTリクエストです。
  • 標準のHTTP「Authorization」ヘッダーを使用してクライアントを認証します。
  • 付加的な「X-Id:」ヘッダーを使用して、クライアントの実装をデバイス種別(例:「Device_1.0」)またはテンプレート登録プロセスで返却された識別子として指定します。
  • リクエスト本体は、コンマ区切り値形式のテキスト行を含みます。各行は、標準の Things Cloud REST APIに対する1件のリクエストに相当します。
  • 応答は常に「200 OK」です。
  • 応答本体も同じく、コンマ区切り値からなる行を含みます。行は、特定のリクエストに関する Things Cloud REST APIからの応答に相当します。

上記の例で言えば、SmartRESTリクエストは以下の通りとなります。

POST /s HTTP/1.1
Authorization: Basic ...
X-Id: Device_1.0

1,200,20.5

これに呼応する応答例として以下が挙げられます。

HTTP/1.1 200 OK
Transfer-Encoding: chunked

20,0

リクエストと応答を照合するため、応答行には、エラーコードの次に、応答に対応するリクエストを示す行が含まれます。この例で言えば、「20」は「OK」を意味し、「0」はリクエストの1行目を指します。

テンプレートの登録方法は?

前述の通り、クライアントは SmartREST を使用する場合、まず、SmartRESTテンプレートがすでにサーバーにとって既知であるかどうかを尋ねます。これは以下のような空のSmartRESTリクエストを使用して行われます。

POST /s HTTP/1.1
Authorization: Basic ...
X-Id: Device_1.0

デバイス実装が既知であれば、応答はIDを返し、このIDはその後のリクエストにおける「X-Id」ヘッダーの「簡略表現」として使用することができます。

HTTP/1.1 200 OK

20,<id>

デバイス実装が未知の場合、応答は以下のようになります。

HTTP/1.1 200 OK

40,"No template for this X-ID"

この場合、あなたのデバイス実装で使用するあらゆるテンプレートを作成します。

POST /s HTTP/1.1
Authorization: Basic ...
X-Id: Device_1.0

10,1,POST,/measurement/measurements,application/vnd.com.nsn.cumulocity.measurement+json,,%%,NOW UNSIGNED NUMBER,"{""time"":""%%"",""type"": ... }
...

この例では、「10」はリクエストテンプレートを指します(一方、「11」は応答テンプレートを指します)。このテンプレートは「1」番ですから、このテンプレートを使用するSmartRESTリクエストは最初のカラムに「1」が付くことになります。このテンプレートはエンドポイント「/measurement/measurements」宛の「POST」リクエストに当たり、コンテンツ種別は「application/vnd.com.nsn.cumulocity.measurement+json」です。このテンプレートで使用されるプレースホルダは「%%」です。プレースホルダはタイムスタンプ(「NOW」)と、符号なし数値および一般数値です。最後に、最終カラムは、入力され送信されることになるリクエストの本体を格納します。

応答はどのように扱われますか?

上記の例ではリクエストとリクエストテンプレートの取り扱いを例示しました。応答の場合、JSONPath表現がThings Cloud REST応答をCSVに変換します。例えば、デバイスがディスプレイを装備し、メッセージを画面に表示可能であると想定しましょう。メッセージを更新するためのオペレーションは以下のような形となります。

{
    "c8y_Message": {
         "text": "Hello, world!"
    },
    "creationTime": "2014-02-25T08:32:45.435+01:00",
    "deviceId": "8789602",
    "status": "PENDING",
    ...
}

クライアント側では、デバイスは主に表示されることになるテキストを知る必要があります。JSONPathでは、以下の構文を使用して「text」プロパティを抽出します。

$.c8y_Message.text

この構文において、「$」はデータ構造のルートを指し、「.」はデータ構造からの要素を選択します。オプションについて詳しくはJSONPathリファレンスをご覧ください。

デバイスは通常、自らに関連する、ペンディング状態のオペレーションをすべて問い合わせます。そうしたクエリに対する Things Cloud の標準応答は以下の通りです。

{
    "operations": [
        {
            "c8y_Message": {
                "text": "Hello, world!"
            },
            "creationTime": "2014-02-25T08:32:45.435+01:00",
            "deviceId": "8789602",
            "status": "PENDING",
            ...
        }, {
            "c8y_Relay": {
                ...
        }
        ...
    ]
]

つまり、応答にはオペレーションのリストが含まれ、これらのオペレーションはさまざまな種類を有する場合があります。そうした構造に対処するには、以下の応答テンプレートを使用します。

11,2,$.operations,$.c8y_Message,$.c8y_Message.text

これは値ごとに説明すると、以下を意味します。

  • 11: これは応答テンプレートです。
  • 2: 番号は2番です。
  • $.operations: この応答はリストであり、リストのプロパティは「operations」です。
  • $.c8y_Message: このテンプレートは「c8y_Message」のプロパティを伴う応答に当てはまります。
  • $.c8y_Message.text: テキストはメッセージから抽出され、返されることになります。

結果、SmartRESTクライアントは以下の応答を返されることになります。

HTTP/1.1 200 OK

2,0,"Hello, world!"

つまり、応答はTemplate 2を使用して作成され、このテンプレートは画面表示メッセージを変換する役割を果たします。応答は最初に送られたリクエストを参照します。実際に設定されるメッセージは「Hello, world!」です。