Intel Edisonで iotkit-commを使うその3:Service SpecificationsとService Queriesについて.

前回のエントリの続き.
前回の説明ではJSONのサンプルとしてしか触れていなかった,Service SpecificationsとService queriesについてのもう少し詳しい説明.

もっと詳しいことを学ぶその3. Service Specifications と queriesについて

Service Specifications と queriesは,分散アプリケーションの開発をシンプルにするiotki-commライブラリの使い方を理解するためのキーだ.iotkit-commで記述された分散アプリケーションは,基本的にサーバとクライアントで構成される.
開発者はService を以下のステップで開発する.

  1. service specification を記述する
  2. specification に基づいたServiceを生成するために,iotkit-commライブラリへリクエストを行う

また,開発者はClientを以下のステップで開発する.

  1. Service query の記述
  2. queryに記述されたAttributesにマッチするServiceの発見と接続をiotkit-commへリクエストする

Service Specifications と queriesはとてもよく似ています.コードについて言えば,Service Specificationsオブジェクトは,Service queryの子となっています.しかし,これらの2つには,根本的な違いが2つあります.

  1. queryはClientによってのみ利用されるのに対して, specificationsはClient,Serverの両者で利用される.Specificationsが初期化や,Serviceへの接続に利用されるが,queryはServiceの発見のみに利用される.
  2. queryはIPアドレスやPortを含むことができないが,対して,Service Specificationは含むことができる.なのでこれらの情報は事前に共有されていないと考えたほうが良い.

ここで,少し脱線するけど,ネットワーク上のServiceを発見することが,どういうことなのかについて詳しく説明をする.
Service発見の機能にともなって,nameやProtocolによる検索を行い,IPアドレスやポート番号を獲得する.Serviceはネットワークでの最初のAdvertiseによってのみ発見される.Service Specificationsのうちの1つがService queryにマッチした時,Serviceを発見した,と言う.Service SpecificationsのAdvertisingとService Queryとのマッチングを管理するプロトコルは,mDNS(Multicast DNS)と呼ばれる.mDNSのコンセプトに基づくために,Service Specifications, query,それらのマッチングはiotkit-commによって抽象化されていることを覚えておいてください.

続いて,Service SpecificationsとQueryの書き方について説明します.これらはJSONで記述されます.

Service Specifications

以下はService Specificationsの例です. 例に続いて各Attributeの説明を行います.

Server Specificationsの例

{
    "name": "/my/home/thermostat/temperature_sensor",
    "advertise": {"locally": true, "cloud": false},
    "type": {
        "name": "zmqpubsub",
        "protocol": "tcp"
    },
    "type_params": {"ssl": false},
    "address" : "127.0.0.1",
    "port": 8999,
    "properties": {"dataType": "float", "unit": "F", "sensorType": "ambient"}
}

各フィールドについての説明

  • name(例外を除いてオプション): 文字列.なるべくユーザフレンドリなものを.Service namesは他のアプリケーションでも表示される可能性がある.
    ※ nameは,もしネットワーク上でServiceがAdvertiseされる場合には設定しなければならない.

  • advertise(オプション): このオプションが設定されない場合,ServiceはLAN内でAdvertiseを行います. ※ 現在のiotkit-commはクラウドでのAdvertising Serviceをサポートしていません.そのため現在は,”cloud”フィールドは無視されてしまいます.

  • type(必須): メッセージの送信受信方法は typeフィールドによって設定されます.typeフィールドは通常,”name”と,”communication plugin”を含みます.iotkit-commでは,プラグインがどのようにメッセージが送信されるかを抽象化するので,開発者はメッセージの内容にフォーカスすることができる.

    • name(必須): このServiceが話すプロトコルの名前を示す.これはまた,利用する通信プラグインの名前にもなる.
    • protocol(必須): トランスポートプロトコルの種別を示す.”tcp”もしくは”udp”のみがサポートされている.
  • type_params(オプション): 通信プラグインがサポートできる設定パラメータ.iotkit-commはこのパラメータをそのまま通信プラグインに引き渡す.

  • port(必須): サーバが動作するポート番号.
  • properties(オプション): Serviceが持つユーザプロパティ.各プロパティは,”name”: valueのペアで記述されなければならない.この場合の例では,センサが周囲の温度を華氏で,FloatでPublishする,という設定を行っている.
  • address(オプション): サーバが動作するアドレス.記述しなければlocalhostが利用される.

このSpecificationはmodule:main.createServiceに渡すことができ,最終的には指定されたアドレスとポートで動作しているServiceのインスタンスを返します.

Service Query

以下にService queryの例を示し,続いて各Propertyの説明を行います.

Server Queriesの例

{
    "name": ".*temperature_sensor",
    "type": {
        "name": "zmqpubsub",
        "protocol": "tcp"
    }
}

このqueryは,Service Specificationセクションで示したSpecificationsと一致していることが大事です.さらに,このqueryはzmqpubsubプロトコルを利用して通信を行う,LAN内の全ての温度センサを発見しに行きます.以上を念頭において各Attributeについて見てみましょう.

各フィールドの説明

  • name(オプション): 正規表現を利用可能.
  • type(必須)
    • name(必須): Serviceが利用する高レイヤの通信プロトコル.これによりClientは,数あるServiceの中から通信可能なものを探すことができる.例えば,type.nameフィールドに zmqpubsub を指定した場合,zmqsubscriber はzmq publishers のみを探すことができる.
    • protocol(必須): トランスポートプロトコル.”tcp”もしくは”udp”のみ利用可能.

このqueryはmodule:main.createClientに渡すことができ,最終的にはServiceに接続されたClientインスタンスが返されます.

Intel Edisonで iotkit-commを使うその2:ServerとClientについて.

前回のiotki-commチュートリアルの "4.もっと詳しいことを学ぶ" の続きです.

もっと詳しいことを学ぶその1. server(Service)の書き方

iotkit-commのチュートリアルその1,Clientについて

以下の3つのステップでService(Server)を作成する

  1. Service Specificationを記述する
  2. 1で決めたSpecificationにもとづいてServiceを作成する
  3. Serviceを実行する

以下でその例について述べる ※以下で示すサンプルコードは,/usr/share/iotkit-comm/examples/node/basic-client-serverに配置されています.

1. Service Specificationを記述する

Service SpecificationはJSONとして記述する.このJSONには,Serivceが動作するポート,Serviceの名前,通信時に利用するプロトコルといったAttributesを記述する.ここでは例として,以下の “server-spec.json”を記述してみる.

{
    “name”: “/ndg/temperature/cpuTemp”,
    “type:”: {
        “name”:”zmqreqrep”,
        “protocol”: “tcp”
    },
    “port”: 8333,
    “properties”: {“dataType”: “float”, “unit”: “F”},
    “advertise”: {“locally”: true, “cloud”: false}
}

2. 1で決めたSpecificationにもとづいてServiceを作成する

例として以下のServiceを作成する(server.js)

var iotkit-comm = require(‘iotkit-comm’);
var path = require(‘path’);
var spec = new iotkit.ServiceSpec(path.join(__dirname, “server-spec.son”);

iotkit.createService(spec, function(service){
    service.comm.setReceivedMessageHandler(function(client, msg, context){
        cnosole.log(“received from client: “ + msg.toString());
        service.comm.sendTo(client, “hi”);
    });
});

※Serviceでは,どのような内容のメッセージかのみを記述するため,そのメッセージが届くかどうかは気にする必要がありません. type.nameフィールドでの記述があれば,iotkit-commはどのようにメッセージを送信すればよいかを判断することができます.(今回の例でいうと”zmqreqrep”) ※ zmqreqrep: ZeroMQ is a high-performance asynchronous messaging library

通信の詳細は,通信プラグインによって処理されます.今回の例で言うと,通信プラグイン(service.comm)は, zmqreqrepプラグインインスタンスです.通信プラグインの詳細は後述しますが,ここでは,通信プラグインは send や,sendTo といったファンクションを提供すると考えてください.
様々な通信プラグイン間の主な違いは,send や, sendTo といったファンクションのコールによって何が起こるかである(例えば,パケットフォーマットやヘッダが異なる).標準でいくつかの通信プラグインがiotkit-commにバンドルされているが,必要に応じて独自の通信プラグインを書くことも簡単にできる.

3. Serviceを実行する

これまでに記述した server-spec.json と, server.js を同じディレクトリに置き,以下のコマンドを実行すればServiceが起動します

node server.js

もっと詳しいことを学ぶその2. client の書き方

iotkit-commのチュートリアルその2,Clientについて

以下の3つのステップでClientを作成する

  1. Service queryを記述する
  2. ServiceのためのQueryにもとづいてClientを作成する
  3. Clientを実行する

以下でその例について述べる ※以下で示すサンプルコードは,/usr/share/iotkit-comm/examples/node/basic-client-serverに配置されています.

1. Service queryを記述する

Service QueryはJSONとして記述する.このJSONには,Clientが接続したいServerのAttributesが記述されている.ここでは例として,以下の “server-query.json”を記述してみる.

{
    "name": "/ndg/temperature/cpuTemp",
    "type": {
        "name": "zmqreqrep",
        "protocol": "tcp"
    },
    "properties": {"dataType": "float", "unit": "F"}
}

2. ServiceのためのQueryにもとづいてClientを作成する

例として以下のclientを作成する(client.js)

var iotkit = require('iotkit-comm');
var path = require('path');
var query = new iotkit.ServiceQuery(path.join(__dirname, "server-query.json"));
iotkit.createClient(query, function (client) {
    client.comm.setReceivedMessageHandler(function (message, context) {
        console.log("received from server: " + message.toString());
        client.comm.send("hello");
    });
    client.comm.send("hello");
});

※ ServiceのIPアドレスや,Serviceとの通信方法をClientが知っている必要はありません.代わりに,Service queryがそのような詳細について管理してくれます.例えば,ClientではServiceの名前とServiceが利用するプロトコル(この場合zmqreqrep)を記述します.Serviceが見つかると,iotkit-commは適切に初期化された通信ハンドル(client.comm)をClientオブジェクトとともに返します.このハンドルは,Serviceに接続されたzmqreqrepプラグインインスタンスです.
通信プラグインの詳細は後述しますが,ここでは,通信プラグインは send や,sendTo といったファンクションを提供すると考えてください.
様々な通信プラグイン間の主な違いは,send や, sendTo といったファンクションのコールによって何が起こるかである(例えば,パケットフォーマットやヘッダが異なる).標準でいくつかの通信プラグインがiotkit-commにバンドルされているが,必要に応じて独自の通信プラグインを書くことも簡単にできる.

3. Clientを実行する

これまでに記述した server-query.json と, client.js を同じディレクトリに置き,以下のコマンドを実行すればClientが起動します

node server.js

動作確認

Tutorial: Server で作成したServerと,このセクションで作成したClientを起動させると,以下のような実行結果が得られます.

f:id:concre_shiitake:20141026234929p:plain

Intel Edisonで iotkit-commを使う:サーモスタットサンプルによるGetting Started

IoTIoT言うとりますけども.
という感じでIntel Edisonに提供されているiotkit-comm.
いかにも!という感じがするライブラリ名だけど,解説記事が全然ないので,ひとまずGettingStartedを訳しながら試してみた.
というわけで,公式ドキュメントを参考にして,話を進めます.

iotkit-comm Getting Started

概要

iotkit-commは以下の様な機能を提供します.これを使うと,クライアント,サーバによって構成される分散アプリケーションの開発ができるようになります.

  • ネットワークに接続されたデバイスの発見
  • ネットワークに接続されたデバイス同士での通信
  • ネットワークに接続されたデバイスとクラウド間での通信

Intel Edison向けのプラットフォームとして設計されていますが,他のプラットフォームでも同様に動作しています.
iotkit-commは,CとNode.js向けのライブラリが存在しますが,以下ではNode.js向けの説明をします.

このドキュメントの読み方

2つのセクションがあるので,目的に応じて利用します.

  • APIリファレンスを閲覧するためのセクションは,”Modules”セクションです.

    • “main”モジュールから読み始めることをおすすめします
  • APIの利用方法についてのチュートリアルを閲覧するためのセクションは,”Tutorial”セクションです.

※ このドキュメントは,Modulesが,Classes, Methods, Variablesのどのような論理構成により実現されるのかを示したものであり,あくまでドキュメントであることに注意してください.コードベースでiotkit-commを説明したものではありません.

このドキュメントでの前提条件

  • Edisonがインターネットアクセス可能であること
    • 前回のエントリを参考にWiFi設定を行いましょう.
  • SampleプログラムやコマンドがEdison上で動作可能であること.
    • 後で記述する,iotkit-commにおけるHelloWorldを試してみましょう.

iotkit-comm ドキュメント(Tutorial編)

Start Here

iotkit-commライブラリを使って開発を行うために,以下のように学習していきます.

  1. iotkit-commのインストール
  2. hello world”プログラムを書いて実行する(オプション)
  3. 付属のサンプルプログラムを実行する(オプション)
  4. もっと詳しいことを学ぶ(オプション)

1. iotkit-commライブラリのインストール

  • Intel Edisonデバイスにはもうインストール済みだからこの手順は必要ないです.

    • 他のプラットフォームへのインストール方法は後日公開予定.
  • ただし,以下の方法でIoT Developer Kit librariesに関するアップデートだけしておきましょう.

$ echo "src intel-iotdk http://iotdk.intel.com/repos/1.1/intelgalactic" > /etc/opkg/intel-iotdk.conf
$ opkg update
$ opkg upgrade

2. Write “hello world”プログラムを書いて実行する

  • “helloworld.js”というJavascriptファイルを作成し,以下のプログラムを記述します.
var iotkit = require(‘iotkit-comm’);
console.log(iotkit.sayhello());
  • 記述した”helloworld.js”の動作をターミナルで確認します.
$ node helloworld.js
# 以下の文字が出力される
>Hello Edison user!

3. サンプルプログラムの実行

  • ※ 公式ページのディレクトリ構成は最新ファームと異なります.以下では,2014/10/26現在での最新ファームである,edison-weekly_build_68_2014-09-08_13-49-07 でのディレクトリ構成を基に話を進めます.
  • この章ではサーモスタットプログラムを試してみましょう.

3-1. 利用するサンプルの概要と補足情報

いくつかの温度センサからのデータを受信するサーモスタットプログラムを試してみます.このプログラムは公式リファレンスでは以下のディレクトリにあるとされていますが,

  • /usr/share/iotkit-comm-js/examples

現在のファームでは以下のディレクトリに移動しています.

  • /usr/share/iotkit-comm/examples/node/distributed-thermostat

3-2. 温度センサの実行

$cd /usr/share/iotkit-comm/examples/node/distributed-thermostat
# 温度センサの起動
$ node temperature-sensor.js
# ターミナル上には特に何も出力されません.

3-3. サーモスタットの実行

  • 3-2とは異なるターミナルを開き,サーモスタットを実行します.
    • 1つのEdison上で実行する場合は,2つのターミナルを開き,それぞれのターミナルからsshでEdisonへ接続すると良いです.
$cd /usr/share/iotkit-comm/examples/node/distributed-thermostat
# サーモスタットの起動
$ node thermostat.js 

3-4. 動作の確認

サーモスタットと温度センサを同時に実行すると,温度センサ(temperature-sensor.js)から送信される温度データを,サーモスタット側(thermostat.js)で受信し,ターミナル上で以下の様な出力が得られます.

# 温度センサ1台数の時
Found new temperature sensor - 127.0.0.1:20408
Received sample temperature 90 from 127.0.0.1:20408
New average ambient temperature (cumulative): 45
Received sample temperature 79 from 127.0.0.1:20408
New average ambient temperature (cumulative): 56.333333333333336
Received sample temperature 67 from 127.0.0.1:20408
New average ambient temperature (cumulative): 59
Received sample temperature 83 from 127.0.0.1:20408
New average ambient temperature (cumulative): 63.8
Received sample temperature 72 from 127.0.0.1:20408
New average ambient temperature (cumulative): 65.16666666666667
Received sample temperature 62 from 127.0.0.1:20408
New average ambient temperature (cumulative): 64.71428571428571

新しいセンサが追加された際も,発見と通信が自動で行われます.

# 途中から温度センサを追加した時
# Found new temperature sensor という所で新しいセンサが検出されています
eceived sample temperature 79 from 127.0.0.1:20408
New average ambient temperature (cumulative): 74.21212121212122
Received sample temperature 63 from 127.0.0.1:20408
New average ambient temperature (cumulative): 73.88235294117646
Received sample temperature 71 from 127.0.0.1:20408
New average ambient temperature (cumulative): 73.8
Found new temperature sensor - 127.0.0.1:54187
Received sample temperature 73 from 127.0.0.1:20408
New average ambient temperature (cumulative): 73.77777777777777
Received sample temperature 61 from 127.0.0.1:54187
New average ambient temperature (cumulative): 73.43243243243244
Received sample temperature 78 from 127.0.0.1:20408
New average ambient temperature (cumulative): 73.55263157894737
Received sample temperature 88 from 127.0.0.1:54187
New average ambient temperature (cumulative): 73.92307692307692
# 温度センサとサーモスタットプログラムをそれぞれ別のEdisonから実行した時.
Received sample temperature 85 from 192.168.11.13:13304
New average ambient temperature (cumulative): 73.75862068965517
Received sample temperature 85 from 192.168.11.13:13304
New average ambient temperature (cumulative): 73.94915254237289

# さらにサーモスタットが動作するEdison上でも温度センサを動作させる
Found new temperature sensor - 127.0.0.1:54453
Received sample temperature 90 from 192.168.11.13:13304
New average ambient temperature (cumulative): 74.21666666666667
Received sample temperature 64 from 127.0.0.1:54453
New average ambient temperature (cumulative): 74.04918032786885
Received sample temperature 87 from 192.168.11.13:13304
New average ambient temperature (cumulative): 74.25806451612904
Received sample temperature 71 from 127.0.0.1:54453
New average ambient temperature (cumulative): 74.2063492063492

4. もっと詳しいことを学ぶ

以下の様な手順で学んで行こう,とされています.後日追記予定.

  1. server の書き方
  2. client の書き方
  3. Service Specifications と queriesについて(重要)
  4. iotkit-commを使って分散アプリケーションを書く方法
  5. cloudにデータをPublishする方法
  6. iotkit-commを利用したソースのUnitテスト方法(未公開)
  7. iotkit-commアーキテクチャについて(未公開)