Raspberry Pi + OpenECHOでLチカ

ここ数日インフルエンザでぶっ倒れておりましたが、リハビリを兼ねて電子工作開始。

さて、自分のとりあえずの目標はRaspberry PiでOpenECHOを使えるようにすることです。その先にもう一個やりたいことがあるのだけれど、とりあえずはここまで。

前回、無事にRaspberry PiでのProcessing起動と、JavaでのGPIO制御ができるようになったので、あとはOpenECHO for Processingのライブラリを突っ込んでやるだけ。ライブラリはここからmasterのzipをとってきて、解凍した中のOpenECHO/OpenECHO for Processing/libraries/の中にある、controlP5ディレクトリとOpenECHOディレクトリを、前回のpi4jと同じように、各ユーザのsketchbook/librariesディレクトリにコピーする。今のところ、pi4jがrootになっていないとGPIO制御できないので、/root/sketchbook/libraries以下にコピーする。これで、/root/sketchbook/libraries以下には、pi4j, OpenECHO, controlP5の3つのライブラリ用ディレクトリが存在しているハズ。

続いて、Raspberry PiをOpenECHOのノードとしてECHONETに参加させるための、Processingのソースの作成。といっても、基本的に組み合わせるだけ。先ほど落としてきたOpenECHOのライブラリに含まれている、/OpenECHO/OpenECHO for Processing/libraries/OpenECHO/examples/Tutorial4_LightEmulator/Tutorial4_LightEmulator.pdeに、pi4jのLチカサンプルコードを組み合わせるだけです。

import java.io.IOException;
import processing.net.*;
import controlP5.*;

import com.sonycsl.echo.Echo;
import com.sonycsl.echo.node.EchoNode;
import com.sonycsl.echo.eoj.EchoObject;
import com.sonycsl.echo.EchoProperty;
import com.sonycsl.echo.eoj.profile.NodeProfile;
import com.sonycsl.echo.eoj.device.DeviceObject;
import com.sonycsl.echo.eoj.device.housingfacilities.GeneralLighting;
import com.sonycsl.echo.processing.defaults.DefaultNodeProfile;
import com.sonycsl.echo.processing.defaults.DefaultController;
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;

color backgroundLightOnColor = color(255, 204, 0);
color backgroundLightOffColor = color(0, 0, 0);
color backgroundNow = backgroundLightOffColor;

GpioController gpio;
GpioPinDigitalOutput lightPin;

public class LightEmulator extends GeneralLighting {

    byte[] mStatus = {0x31};
    byte[] mLocation = {(byte) 0x80};
    byte[] mFaultStatus = {0x42};
    byte[] mManufactureCode = {0x00, 0x00, 0x00};

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

    protected boolean setOperationStatus(byte[] edt) {
        mStatus[0] = edt[0];

        if (mStatus[0] == 0x30) {
            backgroundNow = backgroundLightOnColor;
            lightPin.setState(PinState.HIGH);
        } else {
            backgroundNow = backgroundLightOffColor;
            lightPin.setState(PinState.LOW);
        }

        try {
            inform().reqInformOperationStatus().send();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return true;
    }

    protected boolean setInstallationLocation(byte[] edt) {
        mLocation[0] = edt[0];

        try {
            inform().reqInformInstallationLocation().send();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return true;
    }

    protected byte[] getInstallationLocation() {
        return mLocation;
    }

    protected byte[] getFaultStatus() {
        return mFaultStatus;
    }

    protected byte[] getManufacturerCode() {
        return mManufactureCode;
    }
}

// Use to create GUI
ControlP5 cp5;
LightEmulator lightEmu;

void setup() {

    // Set display window size
    size(400, 400);
    frameRate(30);

    // Set OpenEcho
    try {
        lightEmu = new LightEmulator();
        Echo.start(new DefaultNodeProfile(), new DeviceObject[]{lightEmu});
    } catch (IOException e) {
        e.printStackTrace();
    }

    Echo.addEventListener(new Echo.Logger(System.out));

    // Set pi4j
    gpio = GpioFactory.getInstance();
    lightPin = gpio.provisionDigitalOutputPin(RaspiPin.GPIO_01, "MyLED", PinState.LOW);
    lightPin.low();

} // End of setup()

void draw() {
    background(backgroundNow);
}

ブレッドボードとLEDの配線は、pi4jのLチカサンプルコードに記載のとおり。

最後に、照明(GeneralLighting)としてECHONETに参加したRaspberry Piをコントロールするために、PCをコントローラとしてECHONETに参加させるためのProcessingのソースを作成します。これも、ひょっとしたら/OpenECHO/OpenECHO for Processing/libraries/OpenECHO/examples/Tutorial4_LightEmulator/Tutorial4_LightEmulator.pdeがそのまま使えたのかもしれませんが、前に別に作っていたものを流用して作成。

import controlP5.*;

import com.sonycsl.echo.Echo;
import com.sonycsl.echo.node.EchoNode;
import com.sonycsl.echo.eoj.EchoObject;
import com.sonycsl.echo.EchoProperty;
import com.sonycsl.echo.eoj.profile.NodeProfile;
import com.sonycsl.echo.eoj.device.DeviceObject;
import com.sonycsl.echo.eoj.device.housingfacilities.GeneralLighting;

import com.sonycsl.echo.processing.defaults.DefaultNodeProfile;
import com.sonycsl.echo.processing.defaults.DefaultController;

// Use to create GUI
ControlP5 cp5;

// Set Appliace IP Address
final String targetIp = "192.168.24.210";

GeneralLighting myLight;

static final int GENERAL_LIGHTING = 0;

String[] applianceName = {
    "GeneralLighting"
};

int applianceNum = applianceName.length;

boolean applianceFound[] = {
    false
};

String[] btFnName = {
    "searchAppliances",
    "lightOn",
    "lightOff"
};

String[] btLabel = {
    "Search Appliances",
    "GeneralLighting: ON",
    "GeneralLighting: OFF"
};

void setup() {

    // Set display window size
    size(400, 400);
    frameRate(30);

    myDraw();

    // Set GUI
    textSize(12);
    cp5 = new ControlP5(this);

    int btFnNum = btFnName.length;

    for (int i = 0; i < btFnNum; i++) {

        /* // Processing 2.1.1
        Button bt = cp5.addButton(btFnName[i])
        .setCaptionLabel(btLabel[i])
        .setSize(200,20)
        .setPosition(0,120+30*i);
        */

        // Processing 2.0.3
        ControlP5 bt = new ControlP5(this);
        bt.addBang(btFnName[i], 0, 120 + 40 * i, 100, 20);
        bt.controller(btFnName[i]).setLabel(btLabel[i]);
    }

    // Set OpenEcho
    try {

        Echo.start(new DefaultNodeProfile(), new DeviceObject[]{ new DefaultController() });

    } catch (IOException e) {

        e.printStackTrace();
    }

    Echo.addEventListener(new Echo.Logger(System.out));

    Echo.addEventListener(new Echo.EventListener() {

        public void onNewGeneralLighting(GeneralLighting device) {

            super.onNewGeneralLighting(device);

            if (!device.getNode().getAddress().getHostAddress().equals(targetIp)) {

                println("A GeneralLighting has found, but this is NOT yours.");
                return;
            }

            println("Your GneralLighting has Found!");

            applianceFound[GENERAL_LIGHTING] = true;

            myDraw();

            myLight = (GeneralLighting) device;

            device.setReceiver(new GeneralLighting.Receiver() {

                // Set Callback to get return values

                protected void onSetOperationStatus(EchoObject eoj, short tid, byte esv, EchoProperty property, boolean success) {

                    super.onSetOperationStatus(eoj, tid, esv, property, success);

                    if (!success) {

                        println("error in call reqSetOperationStatus");
                        println("setOperationStatus Param=" + toHexStr(property.edt));
                        return;
                    }

                    showMessage("Success: onSetOperationStatus");
                }

                protected void onGetOperationStatus(EchoObject eoj, short tid, byte esv, EchoProperty property, boolean success) {

                    super.onGetOperationStatus(eoj, tid, esv, property, success);

                    if (!success) {

                        showMessage("error in call reqGetOperationStatus");
                        return;
                    }

                    showMessage("OperationStatus=" + toHexStr(property.edt));
                }

            }); // End of setReceiver

        } // End of onNewGeneralLighting

    }); // End of addEventListener

    // Search controllable appliances
    searchAppliances();

} // End of setup()

void draw() {

};

void myDraw() {

    background(0, 0, 0);

    for (int i = 0; i < applianceNum; i++) {

        if (applianceFound[i]) {

            fill(0, 255, 0); // Green
            text(applianceName[i] + " [FOUND!]", 0, 20 + 20 * i);

        } else {

            fill(255, 255, 255); // white
            text(applianceName[i] + " [NOT FOUND]", 0, 20 + 20 * i);
        }
    }
}

public void searchAppliances() {

    println("—-");

    try {

        // find other devices
        NodeProfile.getG().reqGetSelfNodeInstanceListS().send();

        println("Wait 3 seconds …");

        try {

            Thread.sleep(3000);

        } catch (InterruptedException e) {

            e.printStackTrace();
        }

        println("—-");

        EchoNode[] nodes = Echo.getNodes();

        for (int i = 0; i < nodes.length; i++) {

            EchoNode en = nodes[i];

            println("node id=" + en.getAddress().getHostAddress());
            println("node profile=" + en.getNodeProfile());

            DeviceObject[] dos = en.getDevices();

            println("There are " + dos.length + " devices in this node");

            for (int j = 0; j < dos.length; j++) {

                DeviceObject d = dos[j];

                String typeName = d.getClass().getSuperclass().getSimpleName();

                println("device type = " + typeName);
            }

            println("—-");
        }

    } catch (IOException e) {

        e.printStackTrace();
    }
}

public void lightOn() {

    println("–lightOn–");

    if (applianceFound[GENERAL_LIGHTING]) {

        try {

            myLight.set()
                   .reqSetOperationStatus(new byte[]{0x30}) // Light ON
                   .send();

        } catch (IOException e) {

            e.printStackTrace();
        }

    } else {

        showMessage("There are NO your controllable GeneralLightings.");
    }
}

public void lightOff() {

    println("–lightOff–");

    if (applianceFound[GENERAL_LIGHTING]) {

        try {

            myLight.set()
                   .reqSetOperationStatus(new byte[]{0x31}) // Light OFF
                   .send();

        } catch (IOException e) {

            e.printStackTrace();
        }

    } else {

        showMessage("There are NO your controllable GeneralLightings.");
    }
}

String toHexStr(byte[] arg) {

    String ret = "";

    for (int i = 0; i < arg.length; ++i) {

        ret += Integer.toHexString(arg[i] & 0xff) + " ";
    }

    return ret;
}

void showMessage(String message) {

    myDraw();

    fill(255, 255, 255); // white
    text(message, 0, 350);

    println(message);
}

targetIpの部分は、Raspberry Piの接続環境に応じて変更してください。

さて、これで準備完了。まず、Raspberry Piの方でGeneralLightingSample.pdeを(スーパーユーザ)で実行。続いて、同じローカルネット内のPCで、LightControlSample.pdeを実行。ProcessingのGUI上に”GeneralLighting [FOUND!]”と緑色で表示されていれば、Raspberry PiをECHONETのノードとして発見しており、制御可能な状態です。白色で”GeneralLighting [NOT FOUND”と表示されている場合は、”SEARCH APPLIANCES”ボタンを押してみてください。立ち上げ時にたまたま発見できなかった場合は、これで何度か手動で探しに行くことで見つかるハズです。それぞれ無事プログラムを起動できているにも関わらず、何度やっても見つからない場合は、PCとRaspberry Piの参加しているローカルネットが異なっている可能性があります。

さて、この状態になれば、後はPCのProcessing-GUI上のON/OFFボタンで、LEDのON/OFFができるようになっている…ハズ。自分の場合は、こんな感じになりました。

わかりにくくてすみませんが、マウスでGUIのON/OFF操作をしています。

さてさて、できたものはなんだかショボく見えるかもですが、ここまでできれば、あとはやる気次第でどうとでも拡張できるハズ。

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメント一覧 (1件)

コメントする

目次