Skip to content

ymakino/echowand

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

echowand - Yet Another ECHONET Lite Library for Java

Copyright (c) 2012-2017 Yoshiki Makino

echowand について

Javaを用いた ECHONET Lite ライブラリです。ECHONET Lite 規格を参考にして作成しています。 現在対応している通信方式は、ECHONET Lite 1.1 で規定されている UDP/IP と TCP/IP です。 TCP/IPについては実装は行ってみましたが他システムやデバイスとの通信の試験は行っておりませんので ご注意ください。

echowandはローカルオブジェクトを実装したECHONET Lite デバイスの作成や、リモートオブジェクトの 制御を行うコントローラを簡単に作成するために利用可能なライブラリとなっています。 ここでは、ライブラリを動作させるシステム上で管理されているECHONET Lite オブジェクトのことを ローカルオブジェクト、ネットワーク接続された外部のECHONET Lite デバイス上で管理されている ECHONET Lite オブジェクトのことをリモートオブジェクトと呼ぶことにします。

echowandはフレームの送受信からSETやGET、状変時アナウンスの処理やECHONET Lite オブジェクトの 抽象化までECHONET Liteで必要となる処理の実装を行った様々なクラスからなっていますが、 ライブラリの一部のクラスだけを利用することも可能です。また、様々な処理を担うオブジェクトを 入れ替えることで動作のカスタマイズが可能な設計となっています。

ECHONET Lite について

ECHONET Lite は家電を制御することを目的とし、2011年に公開されたネットワークプロトコル規格です。 詳しくはエコーネットコンソーシアムのページをご覧ください。

ECHONET Lite 規格認証

ECHONET Lite 規格に適合し相互接続性を保証するために エコーネットコンソーシアムでは 認証制度を設けています。

これまで、様々なコントローラやデバイスを作成したりECHONET Liteを利用した実験を行うために echowandを利用していますが、ECHONET Lite 規格認証の申請を行ったことはありません。 また、echowandを利用して作成されたデバイス等が ECHONET Lite 認証を取得することも 可能だと思いますが、現在まで認証を通したという報告は受けていません。

echowandの基本的な使い方

開発環境

echowandはNetBeansを利用して開発しています。その他の環境での動作確認はしておりません。 開発にはOracle JDK 8 を利用していますが、JDK 6以降であれば問題なく動作するはずです。

Coreの生成と初期化

echowand.service.Coreクラス(以下Coreとする)を利用することでライブラリの初期化を 容易に行うことが可能です。もし個別の機能を独立して利用する場合には、Coreを利用せずに 必要なクラスのインスタンスを個別に生成し初期化を行う必要があります。 ここではCoreを利用したライブラリの初期化について説明します。

Coreを初期化する際には、利用するechowand.net.Subnetクラス(以下Subnetとする)の インスタンスを指定します。 例として、ここではIPv4を利用するSubnetであるechowand.net.Inet4Subnetクラス (以下Inet4Subnetとする)を用いて初期化を行います。 Inet4Subnetはインスタンスの生成後、送受信処理を開始するためにstartServiceメソッドが 呼び出される必要があります。便利のため、インスタンスの生成とstartService呼び出しを両方行う startSubnetという静的メソッドが定義されています。 ここではstartSubnetメソッドを利用することにします。

Core core = new Core(Inet4Subnet.startSubnet());

マルチキャストパケット送信に利用するネットワークインタフェースを指定する場合には、 startSubnetメソッドの引数としてネットワークインタフェースのインスタンスを与えます。

NetworkInterface nif = NetworkInterface.getByName("eth0");
Core core = new Core(Inet4Subnet.startSubnet(nif));

Mac OS Xでは、ネットワークインターフェースを指定しても正常に動作しないことがあります。 Mac OS XでIPv4を利用する際には、実行時に以下のオプションを指定することでこの問題を回避できるようです。

-Djava.net.preferIPv4Stack=true

Netbeansのプロジェクトを利用し、プロジェクト実行時にこのオプションを指定したい場合には、プロジェクト・プロパティウィンドウのカテゴリから実行を選択し、上記の行をVMオプションに記述しておきます。

ローカルオブジェクト情報の作成

ECHONET Liteのローカルオブジェクト情報の作成を行います。ここで設定した情報に基づき ローカルオブジェクトが生成されます。 ローカルオブジェクトを利用しないコントローラを実装する場合には本節はスキップしてください。

ローカルオブジェクトを生成するだけでもプロパティデータの送受信は可能ですが、 特殊な処理を行うためにはechowand.object.LocalObjectDelegateechowand.service.PropertyDelegate(以下PropertyDelegateとする)を継承したクラスで 定義します。 ここでは、PropertyDelegateを利用し/sys/class/thermal/thermal_zone0/tempを 温度として返す温度センサを作成します。

class SampleLocalObjectPropertyDelegate extends PropertyDelegate {

    public SampleLocalObjectPropertyDelegate() {
        super(EPC.xE0, true, false, false);
    }

    @Override
    public ObjectData getUserData(LocalObject object, EPC epc) {
        try {
            FileReader fr = new FileReader("/sys/class/thermal/thermal_zone0/temp");
            BufferedReader br = new BufferedReader(fr);
            String line = br.readLine();
            int value = (int) (Double.parseDouble(line) * 10 / 1000);
            byte b1 = (byte) ((value >> 8) & 0xff);
            byte b2 = (byte) (value & 0xff);
            return new ObjectData(b1, b2);
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }
}

ローカルオブジェクト情報を作成するには、最初にechowand.service.LocalObjectConfig (以下LocalObjectConfigとする)のインスタンスを生成します。 作成するローカルオブジェクトのEPCやEOJ等に関する情報はechowand.info.ObjectInfoを 継承したクラスを利用し、LocalObjectConfigのコンストラクタに渡します。 温度センサ用の情報はすでにechowand.info.TemperatureSensorInfoとして作成されているので、 それを利用します。 また、先ほど作成したLocalObjectConfigPropertyDelegateを登録することで、 温度を適切に取得するように設定します。

TemperatureSensorInfo info = new TemperatureSensorInfo();
LocalObjectConfig config = new LocalObjectConfig(info);
config.addPropertyDelegate(new SampleLocalObjectPropertyDelegate());

CoreLocalObjectConfigを登録します。

core.addLocalObjectConfig(config);

ここではローカルオブジェクトの生成に必要な情報を与えるだけであり、実際にローカルオブジェクトが 生成されるのはCorestartServiceが呼び出された時になります。 ここで記述した温度センサの動作プログラムは echowand.sample.SampleLocalObject.java にあります。 2015年10月24日現在、このプログラムはRaspberry Pi(Model B+、2 Model B)のRaspbianで動作することを確認済みです。 その他のモデルでもおそらく問題なく動作すると思いますが動作確認はしていません。

このサンプルプログラムをRaspberry Piで動作させるためには、NetBeansで生成したechowand.jarファイルをRaspberry Piにコピーします。 scpコマンドやUSBメモリ等を利用することで、echowand.jarファイルをRaspberry Piにコピーしてください。 scpを利用する場合には、例えば以下のようなコマンドをNetBeansを利用しているマシンで実行します。 コマンドを実行後、パスワードを聞かれますのでRaspberry Piのパスワードを入力しEnterキーを押します。 この操作例では、Raspberry PiのIPアドレスが192.168.0.1だと仮定しています。

[myname@localhost ~]$ scp Documents/NetBeansProjects/echowand/dist/echowand.jar pi@192.168.0.1:

echowand.jarファイルのコピー後、Raspberry Piにログインします。 Raspberry PiでGUIを利用している場合には、ターミナルを起動してコマンド入力可能なウィンドウを表示します。 必要であれば、cdコマンドを利用してコピーしたファイルの存在するディレクトリに移動してください。 その後、以下の通りコマンドを実行することで温度センサとして動作を開始します。 また、Ctrl-C(Controlキーを押しながらCキーを押す)でプログラムは停止します。

pi@raspberrypi ~ $ java -cp echowand.jar echowand.sample.SampleLocalObject

動作確認のために、NetBeansを利用しているマシン等でechowand.app.ObjectViewerを起動します。 この時、利用するマシンがRaspberry Piと同一のネットワークに接続しており正常に通信が行えることを先に確認しておきます。 echowand.app.ObjectViewer起動時にインタフェース選択ウィンドウが表示されます。 適切なインタフェースを選択しOKボタンを押すと、ObjectViewerのメインウィンドウが表示されます。 192.168.0.1(Raspberry PiのIPアドレス)をクリックしEOJが001101(温度センサ)であるデバイスが存在していることを確認します。 さらに、001101(温度センサ)をクリックすることで、デバイスのプロパティの情報がウィンドウ下部のテーブルに表示されます。 EPCがE0であるプロパティのデータが温度の値となりますので、/sys/class/thermal/thermal_zone0/tempの値と比べてみてください。

値の取得だけではなく、値の設定も可能なもう少し複雑なプログラム例が echowand.sample.SampleLEDLocalObject.java にあります。この例では一般照明(EOJは029001)を実装しRaspberry Pi上のLEDを制御します。 EPCが80であるプロパティの値を30に設定すると点灯、31に設定すると消灯します。

pi@raspberrypi ~ $ java -cp echowand.jar echowand.sample.SampleLEDLocalObject

Coreの処理を開始

ここまでの処理でCoreの作成は完了しますがローカルオブジェクトの生成やその他の初期化等は 行われていません。 startServiceメソッドを呼び出すことで初期化が行われネットワークの送受信処理を開始します。

core.startService();

echowand.service.Service(以下Serviceとする)のインスタンスを利用することで、 ライブラリの多くの機能を利用可能となります。 Serviceのインスタンスは、利用するCoreを引数としてコンストラクタを呼び出すことで行います。

Service service = new Service(core);

doGetを利用したGET処理

ServicedoGetメソッドを利用する方法を説明します。

与える引数の異なるdoGetメソッドが複数あるので、適切なdoGetを選択します。 ここでは、IPアドレスが192.168.0.1のECHONET Liteノードのエアコンの動作状況について 確認する方法を説明します。 エアコンのEOJは013001で、動作状況を表すEPCは0x80です。 また、応答を受信するまでのタイムアウトを1秒とします。

doGetメソッドはechowand.service.result.GetResultクラス(以下GetResultとする)の インスタンスを返します。 GetResultにはGETのリクエストとレスポンスに関する情報が蓄えられます。

Node node = service.getRemoteNode("192.168.0.1");
EOJ eoj = new EOJ("013001");
EPC epc = EPC.x80;
GetResult result = service.doGet(node, eoj, epc, 1000);

このメソッドは応答を待つことなく終了します。 現在の実行状況の確認はGetResultisDoneメソッドで確認できます。応答タイムアウトの前までは falseで、その後はtrueを返します。

応答タイムアウトを待ってから処理を行う場合にはjoinメソッドを利用できます。joinを呼び出すと 応答タイムアウトが発生するまで処理をブロックします。

レスポンスのプロパティデータを調べるときにはcountDatagetDatagetDataListを利用します。 レスポンスのフレームについて調べるときにはcountFramesgetFramegetFrameListを利用します。 例として、レスポンスで取得したデータについて表示するプログラム例を以下に示します。

result.join();

for (int i=0; i<result.countData(); i++) {
    System.out.println("Data " + i + " :" + result.getData(i));
}

以上の動作プログラムは echowand.sample.SampleDoGet.java にあります。

doSetを利用したSET処理

ここではServicedoSetメソッドを利用する方法を説明します。

与える引数の異なるdoSetメソッドが複数あるので、適切なdoSetを選択します。 ここでは、GET処理で説明したエアコンを利用し、エアコンの動作を開始させる方法について説明します。 doGetと異なり、プロパティに設定する値をechowand.common.Dataクラス (以下Dataクラスとする)も指定します。 動作を開始する際にはDataとして0x30を与え、停止する場合には0x31を渡します。

doSetメソッドはechowand.service.result.SetResultクラス(以下SetResultとする)の インスタンスを返します。 SetResultにはSETのリクエストとレスポンスに関する情報が蓄えられます。

Node node = service.getRemoteNode("192.168.0.1");
EOJ eoj = new EOJ("013001");
EPC epc = EPC.x80;
Data data = new Data((byte)0x30);
SetResult result = service.doSet(node, eoj, epc, data, 1000);

例として、レスポンスで取得したデータについて表示するプログラム例を以下に示します。 SETに成功したプロパティについては、空のデータをレスポンスとして受信することになります。

result.join();

for (int i=0; i<result.countData(); i++) {
    System.out.println("Data " + i + " :" + result.getData(i));
}

以上の動作プログラムは echowand.sample.SampleDoSet.java にあります。

doObserveを利用した状変時アナウンス受信処理

ServicedoObserveメソッドを利用する方法を説明します。

与える引数の異なるdoObserveメソッドが複数あるので、適切なdoObserveを選択します。 ここでは、GET処理で説明したエアコンを利用し、エアコンの状変時アナウンス受信時の処理について説明します。 doGetと異なり、タイムアウト時間の設定はありません。

doObserveメソッドはechowand.service.result.ObserveResultクラス (以下ObserveResultとする)のインスタンスを返します。 ObserveResultには、doObserveメソッドで指定した送信元から送られた状変時アナウンスの データの情報が蓄えられます。

Node node = service.getRemoteNode("192.168.0.1");
EOJ eoj = new EOJ("013001");
EPC epc = EPC.x80;
ObserveResult result = service.doObserve(node, eoj, epc);

レスポンスのプロパティデータを調べるときにはcountDatagetDatagetDataListを利用します。 レスポンスのフレームについて調べるときにはcountFramesgetFramegetFrameListを利用します。

例として、10秒間で受信した状変時アナウンスのデータについて表示するプログラム例を以下に示します。

Thread.sleep(10000);

for (int i=0; i<result.countData(); i++) {
    System.out.println("Data " + i + " :" + result.getData(i));
}

ObserveResultの状変時アナウンスの受信を停止する場合には、stopObserveメソッドを呼び出します。

result.stopObserve();

以上の動作プログラムは echowand.sample.SampleDoObserve.java にあります。

RemoteObjectを利用したGET、SET処理

GETやSETの対象となるリモートオブジェクトが1つ、さらに一度にSETやGETを行うEPCの数が1つの場合には echowand.object.RemoteObject(以下RemoteObjectとする)を利用して処理を行うことも可能です。

ECHONET Liteネットワーク内のリモートオブジェクトの一つ一つに対応するRemoteObjectの インスタンスを生成し、そのインスタンスを利用することでGETやSET等の処理が可能となります。

RemoteObjectは先にCore内のechowand.object.RemoteObjectManagerに 登録されている必要があります。 ServicedoUpdateRemoteInfoメソッドを利用することで、ローカルネットワークに存在する リモートオブジェクトの登録を自動的に行うことも可能ですが、 ここでは、192.168.0.1のエアコンを手動で登録することにします。

Node node = service.getRemoteNode("192.168.0.1");
EOJ eoj = new EOJ("013001");
service.registerRemoteEOJ(node, eoj);

RemoteObjectが上書きされてしまうため、同一のオブジェクトの登録を複数回行わないように注意してください。 登録が終わったのでRemoteObjectを取得することが可能となります。

RemoteObject remoteObject = service.getRemoteObject(node, eoj);

RemoteObjectgetDataメソッドを利用してデータをGETできます。getDataObjectDataクラスのインスタンスを返します。

EPC epc = EPC.x80;
ObjectData data = remoteObject.getData(epc);

また、同様にsetDataメソッドを利用してデータのSETができます。

EPC epc = EPC.x80;
ObjectData data = new ObjectData((byte)0x30);
boolean result = remoteObject.setData(epc, data);

以上の動作プログラムは echowand.sample.SampleRemoteGet.javaechowand.sample.SampleRemoteSet.java にあります。

RemoteObjectを利用した状変時アナウンス処理

RemoteObjectを利用した状変時アナウンス処理を行うことも可能です。

状変時アナウンスの処理を行うためにはechowand.object.RemoteObjectObserver (以下RemoteObjectObserverとする)を継承したクラスを作成しRemoteObjectに登録して利用します。

ここではRemoteObjectObserverを継承した匿名クラスのインスタンスを作成し、RemoteObjectに登録してみます。 この匿名クラスは状変時アナウンスのデータを出力します。

Node node = service.getRemoteNode("192.168.0.1");
EOJ eoj = new EOJ("013001");
RemoteObject remoteObject = service.getRemoteObject(node, eoj);

remoteObject.addObserver(new RemoteObjectObserver() {
    @Override
    public void notifyData(RemoteObject object, EPC epc, ObjectData data) {
        System.out.println(object.getNode() + " " + object.getEOJ() + " " + epc + " " + data);
    }
});

以上の動作プログラムは echowand.sample.SampleRemoteObserver.java にあります。

その他の機能

Serviceには他にも以下のような機能があります。

  • doSetGet: SetGet処理を実行
  • doNotify: 状変時アナウンスの送信
  • doCapture: 全送受信フレームの取得 (本機能を利用するためにはSubnetとしてCaptureSubnetを利用する)
  • doUpdateRemoteInfo: ローカルネットワーク内のリモートオブジェクト情報を収集しCoreに登録
  • getLocalData: ローカルオブジェクトのデータ取得
  • setLocalData: ローカルオブジェクトのデータ設定
  • getRemoteData: RemoteObjectを用いてリモートオブジェクトのデータ取得
  • setRemoteData: RemoteObjectを用いてリモートオブジェクトのデータ設定
  • その他

ServiceCoreを利用しないechowandの使い方

echowand.sample.Sample[0-4].java を参照してください。

添付アプリケーション

echowandを利用して作成したリモートオブジェクトの表示ツールを添付しています。

ECHONET Lite ネットワークに接続し、echowand.app.ObjectViewerを起動してみてください。 起動時にネットワークインタフェースを聞かれるので、ECHONET Liteネットワークに 接続しているインタフェースを選択してください。

このアプリケーションの主な機能は以下の通りです。

  • ECHONET LiteデバイスのIPアドレスを左上のリストに表示
  • 選択されたデバイス中に存在するEOJのリストを右上のリストに表示
  • 選択されたEOJオブジェクトの情報を下部のテーブルに表示
  • 右上のEOJをダブルクリックすると、指定されたEOJの情報を新規ウィンドウで表示
  • Set可能なプロパティは、テーブルのセルをダブルクリックすることで編集可能(16進数で記述)

先に説明した通り、Mac OS Xではネットワークインターフェースを指定しても正常に動作しないことがあります。 その場合には、ターミナルでechowandプロジェクトのディレクトリに移動してから、以下のようにechowand.app.ObjectViewerを実行してみてください。

$ java -Djava.net.preferIPv4Stack=true -cp dist/echowand.jar echowand.app.ObjectViewer

注意点

現在開発中であり、全てのクラスやメソッドについて、追加・削除・変更が行われる可能性があります。

相互接続性も考慮して実装を行っていく予定ですが、本ライブラリを用いることで 全ての ECHONET Lite 機器と正しく通信できることを保証するものではありません。

About

Yet Another ECHONET Lite library for Java

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages