Raspberry Pi + OpenECHOでECHOENT Lite機器を自作する【完全版】その②

前回の続きで、Raspberry PiのGPIOを制御するコードを追加していきます。

以下では、前回作成したプロジェクトのコピー(EchoDevicePi)を使って進めていきます。もちろん前回のプロジェクト(EchoDevice)にそのまま追記していく形で進めてもらってOKです。個人的に分けて残しておきたかっただけなので。

では早速。

JavaからRaspberry PiのGPIOを制御するためのライブラリPi4Jをここからもってきます。とりあえず、pi4j-1.0-SNAPSHOT.zipを使うことにします。

“pi4j-1.0-SNAPSHOT/lib/pi4j-core.jar”をEchoDevicePiの下にコピーしてきて、ビルドパスに追加します。

あとはMain.javaとLightEmulator.javaを修正します。

package jp.weblike.makemuda.echodevice;

import java.io.IOException;

import com.pi4j.io.gpio.GpioController;
import com.pi4j.io.gpio.GpioFactory;
import com.pi4j.io.gpio.GpioPinDigitalOutput;
import com.pi4j.io.gpio.PinState;
import com.pi4j.io.gpio.RaspiPin;
import com.sonycsl.echo.Echo;
import com.sonycsl.echo.eoj.device.DeviceObject;
import com.sonycsl.echo.processing.defaults.DefaultNodeProfile;

import jp.weblike.makemuda.echodevice.devices.*;

public class Main {
	public static GpioController gpio;
	public static GpioPinDigitalOutput lightStatusPin;
	public static GpioPinDigitalOutput lightOperationPin;

	static private LightEmulator light;

	public static void main(String[] args) {
		Echo.addEventListener(new Echo.Logger(System.out)); // ログ出力

		gpio = GpioFactory.getInstance();
		lightStatusPin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_00, "LightStatusLED", PinState.HIGH);
		lightOperationPin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_02, "LightOperationLED", PinState.LOW);

		Main mainThread = new Main();
		mainThread.exec();
	}

   void exec() {
        Runtime.getRuntime().addShutdownHook(new Thread() {
            public void run() {
            	lightStatusPin.low();
            	lightOperationPin.low();
            	gpio.shutdown();
                System.out.println("Quit ECHONET Lite Program.");
                System.out.flush();
            }
        });

        try {
        	light = new LightEmulator();	
			Echo.start(new DefaultNodeProfile(), new DeviceObject[]{light});
		} catch (IOException e) {
			e.printStackTrace();
		}
    }
}
package jp.weblike.makemuda.echodevice.devices;

import java.io.IOException;

import jp.weblike.makemuda.echodevice.Main;

import com.sonycsl.echo.eoj.device.housingfacilities.GeneralLighting;

public class LightEmulator extends GeneralLighting {
	byte[] mStatus = {0x31}; // 電源状態を格納する変数です。デフォルトは OFF と仮定します。
	byte[] mLocation = {0x00}; // 機器の置き場所を格納する変数です。
	byte[] mFaultStatus = {0x42}; // 機器に問題が発生した時に、そのコードを格納します。
	byte[] mManufacturerCode = {0, 0, 0}; // ベンダー固有のメーカーコードです。

	@Override
	protected boolean setOperationStatus(byte[] edt) {
		mStatus[0] = edt[0] ; //電源状態が変化したことを他のノードに通知します
		try{
			// ------------------------------------------------------------------
			// この部分に、実際に照明を点灯/消灯させるためのコードを書く。
			if(mStatus[0] == 0x30){
				System.out.println("Light ON!");
				Main.lightOperationPin.high();
				inform().reqInformOperationStatus().send();
			}else if(mStatus[0] == 0x31){
				System.out.println("Light OFF!");
				Main.lightOperationPin.low();
				inform().reqInformOperationStatus().send();
			}else{
				System.out.println("Parameter Error: Can NOT operate status");
			}
			// ------------------------------------------------------------------		
		}catch(IOException e){
			e.printStackTrace();
		}
		return true;
	}

	@Override
	protected byte[] getOperationStatus() {
		return mStatus;
	}

	@Override
	protected byte[] getLightingModeSetting() {
		// TODO 自動生成されたメソッド・スタブ
		return null;
	}

	@Override
	protected boolean setLightingModeSetting(byte[] arg0) {
		// TODO 自動生成されたメソッド・スタブ
		return false;
	}

	@Override
	protected byte[] getFaultStatus() {
		// TODO 自動生成されたメソッド・スタブ
		return mFaultStatus;
	}

	@Override
	protected byte[] getInstallationLocation() {
		// TODO 自動生成されたメソッド・スタブ
		return mLocation;
	}

	@Override
	protected byte[] getManufacturerCode() {
		// TODO 自動生成されたメソッド・スタブ
		return mManufacturerCode;
	}

	@Override
	protected boolean setInstallationLocation(byte[] edt) {
		mLocation[0] = edt[0];
		try{
			inform().reqInformInstallationLocation().send();
		}catch (IOException e) {
			e.printStackTrace();
		}
		return true;
	}
}

lightStatusPinは、プログラムが動作していることを示すためのLEDを光らせておくための制御ピンです。プログラムの開始と同時に点灯、終了と同時に消灯します。lightOperationPinは、ECHONET LiteのON/OFF操作で実際に照明代わりのLEDのON/OFF操作をするための制御ピンです。

ということで、このプログラムは2つのLEDに接続して使うことを想定しています。

Main.javaでスレッドを利用している理由は、Raspberry Pi上でjavaを実行させた後、Ctrl+Cで強制終了させるときにGPIO関係の後始末をさせたかったからです。

プログラムを修正したあとは、実行可能なjarファイルとしてエクスポートして、あとはRaspberry Piに持っていって実行するだけ!…とやれればスマートでカッコ良かったのですが、やってみた結果、プログラムは動くものの、なぜかGPIOの制御がきかず。。。仕方がないので、ソース(Main.javaとLightEmulator.java)とライブラリ(echo.jarとpi4j-core.jar)をRaspberry Piに持ってきて、Rsapberry Pi上でコンパイルして実行することにします。ああ、カッコ悪い。。。ライブラリの参照とかの問題なのだろうけれど。

 

Raspberry Piは事前にJavaを使えるようにしておいてください。自分はこのあたりを参考にJDKを入れましたが、少し時間が経っているので、他にもっとわかりやすい解説サイトがあるかもしれません。

Raspberry Pi上に、適当に”echonet”とかのフォルダを作って、その中に、以下のようにファイルを持ってきます。手段はscpでもsambaでも何でもOKです。

  • Main.java
  • LightEmulator.java
  • lib/echo.java
  • lib/pi4j-core.java

javaファイルにパッケージ云々の記述があると実行時に失敗するので、javacでコンパイルする前に、Raspberry Piに持ってきたMain.javaの1行目と14行目、LightEmulator.javaの1行目と5行目はコメントアウトしておいてください。ああカッコ悪い。。。

ファイルを置いたディレクトリに移動してきたら、javacでコンパイルします。

$ javac -cp lib/echo.jar:lib/pi4j-core.jar Main.java LightEmulator.java

日本語のコメント関係でエラーが出てくるようであれば、eclipseのテキストのエンコードがUTF-8になっている確認してください。

無事にclassファイルが生成されたら、以下で実行です。

$ sudo java -cp .:lib/echo.jar:lib/pi4j-core.jar Main

特に問題なければ、PCで実行したときと同じようなログが出力されるはずです。Raspberry PiとAndroid端末を同じローカルネットに繋いでいれば、Kadecotで新しいGeneralLightingが発見されます。

OpenEchoTest

こんな感じで配線してもらえたら、プログラムの開始と同時に赤色LEDが点灯し、KadecotからのON/OFF操作で緑色LEDが点灯/消灯するはずです。Ctrl+Cで強制終了すると、両LED共に消灯します。

 

思ったよりつまづいた上に、大変カッコ悪い進め方になってしまいました。。。完全版をうたっておきながら。

とりあえず使えるものをつくるため、ラスト、Raspberry Piの電源ONで、このプログラムが自動スタートするようにしたいと思います。