ユーザ&プログラマ・マニュアル¶
インデックス¶
APIの概要¶
この節では、この IoTAgent によって実装されたサウスバウンド API について説明します。Configuration API および一般的な IoTAgent に関するその他の APIについては、API リファレンスのセクションをチェックしてください。
Ultralight 2.0 プロトコル¶
説明¶
Ultralight 2.0 は、帯域幅とデバイスのメモリが限られたリソースになる場合がある、制約のあるデバイスとの通信を目的とした、軽量のテキストベースのプロトコルです。
測定のペイロード構文¶
情報更新のリクエストのペイロードは、'|' キャラクタで区切られたキーと値のペアのリストで構成されます。例えば :
t|15|k|abc
この例では、2つの属性が送信されます。つまり、値 "15" の名前 "t" と値 "k" の名前 "abc" です。Ultralight 2.0の値は型を持ちません。すべてが文字列として扱われます。
'#'文字を使用して、複数の測定値グループを1つのリクエストにまとめることができます。その場合、測定値のそれぞれのグループに対して異なる NGSI リクエストが生成されます。例えば :
gps|1.2/3.4#t|10
これにより、同じエンティティに対して2つの NGSI リクエストが生成されます。値のそれぞれに対して1つです。これらのリクエストのそれぞれには、任意の数の属性を含めることができます。
測定値グループには、次の構文を使用してオプションのタイムスタンプを追加することができます :
2016-06-13T00:35:30Z|lle|100
タイムスタンプは、測定値自体のプレフィックスとして '|'で区切られて追加されます。属性は最終エンティティの TimeInstant
属性に変換されます。
アクティブ属性とパッシブ属性¶
現在のバージョンのエージェントは、アクティブな属性、つまりデバイスによってエージェントにアクティブにレポートされた属性のみをサポートします。パッシブまたはレイジー (lazy) な属性、つまり、エージェントからの明示的リクエストでのみ与えられる属性は実装されません。その実装に関する詳細と更新については、問題#23を確認してください。
コマンドの構文¶
コマンドは、IotAgent からデバイスに送信されるメッセージです。コマンドの形式は次のとおりです :
<device name>@<command name>|<command value>
これは、Context Brokerで device_name
と名付けれたデバイスが、command_name
コマンドを所定の値で実行する必要があることを示します。例えば :
Robot1@turn|left
この例では、ロボット1に左に向けるよう指示します。
パラメータを必要とする複雑なコマンドの場合、パラメータ渡しを実装するために command_value
を使用できます。例えば :
weatherStation167@ping|param1:1|param2:2
この例では、weatherStation167
に提供されたパラメータでpingメッセージに返信するよう指示します。=
はContext Brokerの禁止文字のため、:
の代わりに =
を使用することができません。
コマンドがデバイスで実行されたら、サーバへのリプライは次の形式に従わなければなりません。
<device name>@<command name>|result
ここで、device_name
と command_name
は、コマンド実行で使用されたものと同じものでなければならず、結果はコマンドの最終結果です。例えば :
weatherStation167@ping|Ping ok
この場合、Weather stationはすべてが正常に機能していることを示す文字列の値でリプライします。
双方向構文¶
Provisioning API の最新バージョンでは、Context Broker とデバイスの間で共有されるデータを同期して保持するために、リバース表現の定義が可能です。これは、データがデバイスからのプレーンデータか、IoTAgentのトランスフォーメーション表現かを問いません。この場合、リバース表現が定義されると、双方向属性が変更されるたびに、 IoTAgent は元のデバイスに、リバース表現の属性で定義された名前とデバイスのIDを持つコマンドを送信します。上のコマンド構文を参照してください。
トランスポート・プロトコル¶
Ultralight 2.0 は、デバイスとサーバ間で共有する測定値とコマンドを記述するペイロードを定義しますが、単一のトランスポートプロトコルは指定していません。代わりに、サマリシナリオでさまざまなトランスポートプロトコルバインディングを確立できます。
以下のセクションでは、現在サポートされているバインディングの HTTP, MQTT, AMQP について説明します。
HTTPバインディング¶
HTTPバインディングには、GET要求、POST要求、およびコマンドの3つの相互作用が定義されています。
GET要求によるリクエスト¶
デバイスは、次のクエリパラメータを使用して、/iot/d
パスに HTTP GET 要求により、IoT Platform に新しい測定値を報告できます :
- i (device ID) : デバイスID。APIキーで一意
- k (API Key) : APIデバイスが登録されているサービスのキー
- t (timestamp) : 測定値のタイムスタンプ。IoTAgentの 自動タイムスタンプを無効にします (オプション)
- d (Data) : Ultralight 2.0 ペイロード
GET要求のペイロードには、複数の測定値グループを含めることはできません。
POST要求によるリクエスト¶
測定値の報告方法のもう1つの方法は、POST 要求を使用して報告することです。この場合、ペイロードはリクエスト・ペイロードとして渡されます。2つのクエリ・パラメータは必須です :
- i (device ID) : デバイスID。API キーで一意
- k (API Key) : デバイスが登録されているサービスの API キー
- t (timestamp) : 測定値のタイムスタンプ。IoTAgent の自動タイムスタンプを無効にします(オプション)
コマンドの送信¶
HTTPトランスポートを使用する場合、コマンド処理には2種類があります :
-
Push commands : この場合、デバイスには、Iot Agent が受信したコマンドを送信するURLを含む、
endpoint
属性をプロビジョニングする必要があります。リクエスト・ペイロード形式は、UL プロトコル記述に記述された形式になります。デバイスは、UL2.0 結果形式のコマンドの結果を含む 200 OK レスポンスで応答します。 -
Polling commands : この場合、エージェントはデバイスにメッセージを送信せず、デバイスがコマンドを取得する準備ができたらいつでも IoT Agent からメッセージを取得する責任があります。Iot Agent からコマンドを取得するために、デバイスは、通常の測定値の一部として値 '1' を持つクエリパラメータ 'getCmd' を送信します。このアクションの結果、 IoTAgent は、空のボディ(測定レポートへの典型的な応答)を返す代わりに、文字 '#'で区切られた、デバイスで利用可能なすべてのコマンドのリストを返します。コマンド・ペイロードは、プロトコルセクションおよびプッシュコマンドとの共有に記述されています。デバイスがコマンドの実行を完了すると、デバイスは測定結果が報告されるのと同じ方法で応答を送信しますが、プロトコルセクションで公開している、コマンドの結果形式を使用します。
ポーリングコマンドに関するいくつかの追加の注釈 :
- 測定値を送信することなくコマンドを取得することもできます。言い換えれば、デバイスは、蓄積されたコマンドを得るために測定値を送信するよう強制さません。
MQTTバインディング¶
MQTT は、マシン間(M2M) / IoT 接続プロトコルであり、ピア間の軽量な相互作用にフォーカスしてます。MQTTは、ユーザによって定義された階層的なトピック・セットに対するパブリッシュ/サブスクライブ・メカニズムに基づいています。
このセクションでは、MQTT をUltralight 2.0 のトランスポート・プロトコルとして使用する場合に許可されるトピックとメッセージを指定します。MQTT プロトコルで使用されるすべてのトピックには、同じプレフィックスが含まれています :
<apiKey>/<deviceId>
ここで、<apiKey>
はサービスに割り当てられたAPIキー、<deviceId>
はデバイスのIDです。
このトランスポート・プロトコル・バインディングはまだ開発中です。
1つの測定値を1つのメッセージで送信¶
サーバに単一の測定値を送信するには、デバイスはプレーン値を次のトピックにパブリッシュする必要があります :
<apiKey>/<deviceId>/attrs/<attrName>
ここで、ここで、<apiKey>
と <deviceId>
は典型的な意味を持ち、<attrName>
はデバイスが送信している測定の名前です。
また、たとえば、IDが id_sen1
、APIキーが ABCDEF
、属性IDが h
と t
のデバイスで Mosquitto を使用している場合、湿度の測定値は次のように報告されます :
$ mosquitto_pub -t /ABCDEF/id_sen1/attrs/h -m 70 -h <mosquitto_broker> -p <mosquitto_port> -u <user> -P <password>
1つのメッセージで複数の測定値を送信¶
1つのメッセージで複数の測定値を送信するには、次のトピックでメッセージを発行する必要があります :
<apiKey>/<deviceId>/attrs
ここで、<apiKey>
と <deviceId>
は一般的な意味を持っています。このようなメッセージのペイロードは、測定値グループの有無にかかわらず、Ultralight 2.0 ペイロードでなければなりません。
たとえば、IDが id_sen1
のデバイスで Mosquitto を使用している場合、ABCDEF
のAPIキーと h
と t
の属性 ID を入力すると、すべての測定値(湿度と温度)が次のように報告されます :
$ mosquitto_pub -t /ABCDEF/id_sen1/attrs -m 'h|70|t|15' -h <mosquitto_broker> -p <mosquitto_port> -u <user> -P <password>
コマンド¶
MQTTトランスポート・プロトコル・バインディングを使用するコマンドは、常にプッシュ・モードで動作します。サーバは、デバイスによるサブスクライブされているトピック、つまり、コマンド・トピックにメッセージをパブリッシュします。デバイスがコマンドを終了すると、その結果が別のトピックにパブリッシュされます。
コマンド・トピック、ここでサブスクライブされたクライアントは、次の形式を持ちます :
<apiKey>/<deviceId>/cmd
コマンドの結果は、次のトピックで報告する必要があります :
<apiKey>/<deviceId>/cmdexe
コマンドの実行とコマンド・レポートのペイロード形式は、上記の"Ultralight 2.0コマンド構文"で指定されています。
例えば、ユーザが data = 22
パラメータを有する ping
コマンドを送信したい場合、ユーザは、sensor
型の sen1
と呼ばれるエンティティに関する以下のリクエストを Context Broker に送信します :
{
"updateAction": "UPDATE",
"contextElements": [
{
"id": "sen1",
"type": "sensor",
"isPattern": "false",
"attributes": [
{
"name": "ping",
"type": "command",
"value": "22"
}
]
}
]
}
デバイスに関連付けられたAPIキーが ABCDEF
で、sen1
エンティティに関連するデバイスIDが id_sen1
である場合、これにより、/ABCDEF/id_sen1/cmd
トピックのメッセージが次のペイロードとともに生成されます :
id_sen1@ping|22
Mosquitto を使用している場合、mosquitto_sub
スクリプトを実行することによってそのようなコマンドが受信されます :
$ mosquitto_sub -v -t /# -h <mosquitto_broker> -p <mosquitto_port> -u <user> -P <password>
/ABCDEF/id_sen1/cmd id_sen1@ping|22
この時点では、Context Brokerは、sen1
エンティティの ping_status
の値を PENDING
に更新します。ping_info
と ping
はどちらも更新されません。
デバイスがコマンドを実行すると、その結果を次の形式のペイロードを持つ /ABCDEF/id_sen1/cmdexe
トピックにパブリッシュできます :
id_sen1@ping|1234567890
Mosquitto を使用している場合、そのようなコマンドの結果は、mosquitto_pub
スクリプトを実行して送信されます :
$ mosquitto_pub -t /ABCDEF/id_sen1/cmdexe -m 'id_sen1@ping|1234567890' -h <mosquitto_broker> -p <mosquitto_port> -u <user> -P <password>
最後に、Context Brokerは、ping_info
と ping_status
の値をそれぞれ 1234567890
と OK
に更新します。ping
属性は更新されません。
AMQPバインディング¶
AMQP は、Advance Message Queuing Protocol の略で、メッセージ・キュー・システムで最も一般的なプロトコルの1つです。プロトコル自体はソフトウェアに依存せず、優れたアーキテクチャ上の柔軟性を実現しますが、このトランスポート・バインディングは、RabbitMQ Broker と連携するように設計されています。前の項の MQTT バインディングに非常に似ています。実際、スケーラブルな MQTT Broker を必要とするIoT Platform のデプロイメントでは、MQTT プラグインを使用した RabbitMQ が使用され、AMT を介して Iot Agent を RabbitMQ に接続し、クライアントをMQTTを介して RabbitMQ に接続します。
バインディングは Iot Agent をエクスチェンジ (通常は amq.topic
) に接続し、2つのキュー(クラスタ環境の IoTAgent のすべてのインスタンス間で共有する)を作成します。1つは着信測定値用、もう1つはコマンド結果更新メッセージ用(_commands
サフィックスを追加し、測定値キューとして名付ける)。
バインディングは Iot Agent をエクスチェンジ (通常は amq.topic
) に接続し、2つのキュー(クラスタ環境の IoTAgent のすべてのインスタンス間で共有する)を作成します。1つは着信測定値用、もう1つはコマンド結果更新メッセージ用(_commands
サフィックスを追加し、測定値キューとして名付ける)。
Key pattern | Meaning |
---|---|
. |
Multiple measure reporting |
. |
Single measure reporting |
. |
Command reception |
. |
Command update message |
ペイロードは他のバインディングと同じです。
新しいトランスポートの開発¶
Ultralight 2.0 Iot Agent は、同じ Ultralight 2.0 ペイロードに対して複数の異なるトランスポートを処理できます。これらのトランスポートは、エージェントの起動時に、Node.js モジュールの lib/bindings
フォルダを調べることで動的にロードされます。これらのモジュールは、次のフィールドをエクスポートする必要があります :
-
deviceProvisioningHandler(device, callback) : このハンドラは、新しいデバイスが Iot Agent にプロビジョニングされるたびに呼び出されます。デバイスオブジェクトには、デバイス登録で提供されたすべての情報が含まれます
-
configurationHandler(configuration, callback) : デバイスグループ内の変更(プロビジョニングまたは更新)のハンドラ。このハンドラは、構成グループがプロトコル・バインディングで初期化または登録を必要とする場合に使用する必要があります
-
start(newConfig, callback) : 指定された構成でバインディングモジュールを開始します。
newConfig
オブジェクトは、グローバルエージェント設定が含まれています。モジュールは、グローバルスコープ内の特定の属性を使用して、グローバル構成スコープ自体を使用する代わりに、すべての構成値を保持する必要があります -
stop(callback) : バインディングモジュールを停止します
-
protocol : このフィールドには、プロトコルを識別する文字列キーが含まれていなければなりません。サーバからのリクエスト(コマンドとパッシブ属性)は、デバイスの
protocol
フィールドとモジュール内の対応するprotocol
属性を使用して、どのモジュールをリクエストに参加させるべきかを識別します
すべてのメソッドは、エラーの有無にかかわらず、終了する前にコールバックを呼び出す必要があります。バインディングは、 Iot Agent Node.js ライブラリのメソッドを使用して、着信リクエストを処理するために使用します。
開発ドキュメント¶
プロジェクトビルド¶
プロジェクトはGrunt Task Runnerを使用して管理されます。
使用可能なタスクのリストについては、次のように入力します。
grunt --help
次のセクションでは、使用可能なオプションについて詳しく説明します。
コーディング・ガイドライン¶
jshint, gjslint
提供された .jshintrc および .gjslintrc フラグファイルを使用します。後者は Python を必要とし、grunt-init を使用してプロジェクト・スケルトンを作成する際にその使用を無効にすることができます。ソースコードのスタイルを確認するには、次のように入力します。
grunt lint
Checkstyle レポートは Jenkins と一緒に使用して、Checkstyle プラグインと Violations プラグインを使用してプロジェクト品質メトリックを監視することができます。report/lint/
下に Checkstyle と JSLint のレポートを生成するには、次のように入力します。
grunt lint-report
継続的なテスト¶
src ファイルまたはテストを変更して、継続的なテストをサポートします。連続テストの場合は、次のように入力します。
grunt watch
ソースコードのドキュメント¶
dox-foundation
HTML ドキュメントを site/doc/
の下に生成します。DocLinks プラグインを使用して jenkins
と一緒に使用できます。ソースコードのドキュメントをコンパイルするには、以下を入力します。
grunt doc
コードカバレッジ¶
Istanbul
テストのコードカバレッジを分析します。
site/coverage/
の下にHTMLカバレッジレポートを生成し、サマリを出力するには、次のように入力します。
# Use git-bash on Windows
grunt coverage
report/coverage/cobertura-coverage.xmlCobertura
プラグインを使用して Jenkins でプロジェクト品質メトリクスを監視するために使用できる Cobertura レポートを生成するには、次のように入力します。
# Use git-bash on Windows
grunt coverage-report
コードの複雑さ¶
Plato
Plato を使用してコードの複雑さを分析し、そのレポートを site/report/
の下に保存します。DocLinksプラグインを使用して jenkins と一緒に使用できます。複雑さのレポートでは、次のように入力します。
grunt complexity
PLC¶
プロジェクトの貢献者を更新
grunt contributors
開発環境¶
git hooks で環境を初期化してください
grunt init-dev-env
すべての開発者のためにこのタスクを自動的に実行することを強くお勧めします。package.json
に次の行を追加するだけです。
lines to your package.json
{
"scripts": {
"postinstall": "grunt init-dev-env"
}
}
サイト生成¶
プロジェクトの GitHub ページを生成し、カバレッジ、複雑さ、および JSDocs のページを公開するという面倒な作業があります。GitHub ページを初期化するには、以下を使用します :
grunt init-pages
これにより、リポジトリのルートの下にサイトフォルダも作成されます。このサイトフォルダはリポジトリの履歴から切り離され、公開のために作成された gh-pages ブランチに関連付けられています。この初期化アクションは、プロジェクト履歴で一度だけ実行する必要があります。サイトが初期化されたら、次のコマンドで公開します :
grunt site
このコマンドは、開発者が init-dev-env を実行した後にのみ動作します。これは、分離サイトを作成することが目的です。
このコマンドは、カバレッジ、ドキュメント、および複雑なタスクも起動します。上記のセクションを参照してください。