CoAP Server サンプルコード (Java)

Constrained Application Protocol

IoTで求められる省電力に対応するプロトコルとして、Constrained Application Protocol 略してCoAPと呼ばれるものがあります。
UDPを使用しヘッダおよび通信制御の容量を削減し、フォーマットとしてHTTPとのマッチングを可能としているところが特徴ですが、HTTPライクな割にクライアントからサーバへのリクエストだけではなく、サーバから定期的にデータをPUSHされる"observe"という機能があったり、プロトコルの実装としては複雑です。

ただ一般には決して利用されないようなこのCoAPにもいくつかのフレームワークが存在し、実装に悩む必要はありません。
今回はフレームワークの一つであるCaliforniumを利用したサーバのサンプルプログラムを作成します。

build.gradle

gradleでCaliforniumをビルドします。Eclipseのプロジェクトであっても、IDEはIntellijでも当然動作します。

dependencies {
    compile 'org.eclipse.californium:californium-core:2.3.0'
    compile 'org.slf4j:slf4j-log4j12:1.7.30'
}

Californiumだけビルドすれば動作に問題はありませんが、それだけだと動作時にログ出力先がないとエラーがでるのでslf4jもビルドしておきます。

リクエスト受信時の動作設定

指定パスへのリクエスト

指定されたパス(例えば"coap://localhost/Hello")にリクエストを受信した場合の動作を記述します。
CoapResourceクラスにパス名を渡すことでパスを設定します。

class HelloResource extends CoapResource {

    public HelloResource() {
        super("Hello");     //パスの指定
    }

    @Override
    public void handleGET(CoapExchange exchange) {
        //応答動作。この場合は"World"を返信。
        exchange.respond("World");
    }
}
observeリクエスト

observeのRegistrationを受信した場合の動作を記述します。 Timerで応答周期を設定している点を除き、通常のパス指定のときと記述内容は変わりません。

public class ObservableResource extends CoapResource {
    private String currentTimeString;
    static final private SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public ObservableResource() {
        super("obs");   //パスの指定

        setObservable(true);
        setObserveType(CoAP.Type.CON);

        Timer timer = new Timer();
        //応答周期設定
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                resetCurrentTIme();
                changed();
            }
        }, 0, 5000);
    }

    private void resetCurrentTIme() {
        Date currentDate = new Date();
        currentTimeString = DATE_FORMAT.format(currentDate);
    }

    @Override
    public void handleGET(CoapExchange exchange) {
        ////応答動作。この場合は現在時刻を返信。
        exchange.respond(currentTimeString);
    }
}

mainクラス

サーバの受信IPアドレスを設定し、パスごとのリクエストクラスを追加します。

public class CaliforniumServer extends CoapServer {
    private static final int COAP_PORT = NetworkConfig.getStandard().getInt(NetworkConfig.Keys.COAP_PORT);

    public static void main(String[] args) {
        CaliforniumServer server = new CaliforniumServer();
        server.addEndpoints();

        //パスごとの受信動作追加
        ObservableResource observable = new ObservableResource();
        HelloResource hello = new HelloResource();

        server.add(observable, hello);
        server.start();
    }

    private void addEndpoints() {
        Collection<InetAddress> addresses = addresses = NetworkInterfacesUtil.getNetworkInterfaces();
        NetworkConfig config = NetworkConfig.getStandard();

        for(InetAddress address : addresses) {
            InetSocketAddress bindToAddress = new InetSocketAddress(address, COAP_PORT);
            System.out.println(bindToAddress.toString());
            CoapEndpoint.Builder builder = new CoapEndpoint.Builder();
            builder.setInetSocketAddress(bindToAddress);
            builder.setNetworkConfig(config);
            addEndpoint(builder.build());
        }
    }
}