CPとcloudBitでIoT - 3.cloudBitからの情報受け取り口


cloudBitからのデータはsubscription(定期購読)という仕組みを使って受け取ることができます。subscriptionとは、cloudBitが直接(cloudBitからの値を使いたい)アプリケーションにアクセスするのではなく、cloudBitの値を受け取りたいエントリポイント(URL)をlittleBits社のクラウドに登録しておくと(雑誌の定期購読の申し込みと一緒です)、cloudBitはlittleBits社のクラウドに値を送信する(雑誌で言えば最新号が出る)、littleBits社のクラウドは登録しておいたエントリポイントに値を送信する(最新号を登録済みの読者に送付する)という仕組みをとっています。

そんなしち面倒くさいことをしなくても、直接自分のアプリケーションにデータを送ってくれればいいじゃないか、と考えてしまうかもしれませんが、それでは、アプリケーション(正確にはエントリポイント)が変わるたびに、cloudBitの中のデータ送信先アドレスを変更する必要が生じてしまいます。むしろ、cloudBitからは常に同じ場所にデータを送信し、データを受け取った側(littleBits社のクラウド)の側で、最新の購読状況を元にデータを再配信するほうが、遠く離れて今ごろどこにあるか分からないcloudBit内のエントリポイント書き換えで苦労するよりは、よっぽど効率的(少なくとも汎用的)という考えです。

さて、APIドキュメントにある実行例(ちょっとわかりにくいのですが、POSTed to subscriberと書いてある箇所です)を見ると、
{
device_id:"000001", user_id:<Int>, timestamp:<Int>, type:"amplitude",
payload: {absolute:*, percent:*, delta:*, level:*}
}


{
device_id:"000001", user_id:<Int>, timestamp:<Int>, type:'amplitude',
payload: {absolute:*, percent:*, delta:'ignite', level:*}
}

さらに
{
device_id:"000001", user_id:<Int>, timestamp:<Int>, type:'amplitude',
payload: {absolute:*, percent:*, delta:'sustain'|'ignite', level:*}
}

といったJSON形式でcloudBitからのデータがsubscribe先に送信される仕様のようです。

そこで、これらの情報を格納するための器として、次のようなメンバ変数を持つCloudbitEventクラスを定義することにします。

public class CloudbitEvent {
    private String eventId;
    // device_id:"000001"
    private String eventBitId;
    // user_id:<Int>
    private int eventUserId = -1;
    // timestamp:<Int>
    private int eventTimestamp = -1;
    // type:"amplitude"
    private String eventType;

    // payload
    // absolute:*
    private int payloadAbsolute = -1;
    // percent:*
    private int payloadPercent = -1;
    // delta:'ignite', 'sustain' | 'ignite'
    private String payloadDelta;
    // level:*
    private String payloadLevel;
}

数値系のメンバ変数には初期値として-1を設定しています。littleBitsクラウドからの通知中で値が未設定であれば-1を保持しておくようにしておきましょう。なお、先頭のeventIdはデータベースに格納する際のユニークキーを想定しています。エントリポイントはlittleBitsクラウドから呼び出されるので、呼び出し時に画面出力を行うというよりは、一旦データベースに値を格納しておき、後で必要に応じて画面表示を行うという流れになります。

各メンバ変数にはアクセサとなるgetterとsetterを用意しておくことにします。動作確認用のtoString()メソッドも(Eclipseであれば自動生成して)用意しておきましょう。ここまでは前回のCloudbitクラスと同様ですね。

さて、subscriptionの口、つまりlittleBitsクラウドからの呼び出し口を用意する必要があります。littleBitsクラウドからの呼び出しを受ける、ということは

  • HTTP POSTメソッドを受け取ることができ、
  • littleBitsクラウドから見える場所、別の言い方をすればfirewallの外側
  • 起動の度に接続先が変わらないこと(DNSで解決可能なサーバ名か固定IP)

である必要があります。ここでのお勧めはSAP HANA Cloud Platformです。何が素晴らしいって、インメモリプラットフォーム(単にインメモリの高速DBだけではなく、アプリケーションサーバとしてサーバサイドJavaやJavaScriptが動作する環境などなどてんこ盛りの一式)が開発者ライセンス無償で利用できるという気前の良さです。

littleBitsクラウドからの呼び出しを受ける口としてCloudbitSubscriptionServletクラスを定義することにします。littleBitsクラウドからの呼び出しはHTTP POSTメソッドなので、受け口の実装は次のような感じになります。

@WebServlet("/Cloudbit")
public class CloudbitSubscriptionServlet extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
    }
}

doPost()は現在は未実装の空メソッドですが、ここに受け取ったデータをデータベースにINSERTするようなコードを次回入れていきましょう。

さて、せっかくですので、doGet()メソッドも用意しておけば、Webブラウザ上でURLに /Cloudbit を指定することでそれまでに取得したデータを表示する、なんてこともできます。

    protected void doGet(HttpServletRequest request, HttpServletResponse response) 
            throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        PrintWriter writer = response.getWriter();
        writer.println("<html><head>");
        writer.println("<title>Cloudbit Sensor Data stored in HCP</title>");
        writer.println("</head>");
        writer.println("<body>");
        writer.println("<h1>Cloudbit Sensor Data stored in HCP.</h1>");
        writer.println("</body>");
        writer.println("</html>");
    }

ここではとりあえずタイトルらしきものを出力しておくようにしました。

今回はブラウザ上でこのdoGet()メソッドの出力画面が見られるところまでできれば、動作検証できた、ということにしておきましょう。

例によって、ソースコードに関しては、github上でcloudbit-javaプロジェクトを構築しました。さらに今回使った内容に関しては、2-CloudBit_DBブランチにて、動作・参照可能なソースコードを公開させて頂いております。

それでは続きはまたにしましょう!

  1. はじめに
  2. cloudBitの情報取得
  3. cloudBitからの情報受け取り口
  4. 受け取ったデータをDBに格納