HTML5からMQTTに接続する方法

## 概要
IoT機器のセンサーの測定結果をリアルタイムに表示したい。しかし、Javaアプレットを使うとJava実行環境(JRE)のバージョンの問題やら公的機関の証明書を使って署名が必要となるなど、何かと問題が多い。 そこで、HTML5とJavaScriptを使えば、簡単に実現できて、コードに署名も必要がない。 どうやって実現するか確認してみました。


## システム構成
システム構成の概要図は、こんな感じです。 ラズパイに温度・湿度センサー、大気圧センサー、電力モニターを接続したIoT機器相当の装置から、クラウド上のMQTTブローカーにデータを送信します。 HTML5対応ブラウザ上で動作するJavaScriptから、MQTTブローカーに接続して、ブラウザ画面上にデータを表示するものです。
![System-Diagram.png](https://qiita-image-store.s3.amazonaws.com/0/42829/acd6fc58-82bb-672b-2917-3d4c213118a4.png)

今回は、MQTTブローカーのWebSockets対応とブラウザ上のJavaScriptのコードを中心に、記述します。それからラズパイの電子工作部分は、別の機会にご紹介したいと思います。


## MQTTブローカーのWebSockets対応

MQTTブローカーとして Mosquitto 1.4.5 を利用します。クラウド上のLinux仮想サーバーへの導入方法は、http://mosquitto.org/download/ のぺージを参照して実施します。
Ubuntu14.04 への Mosquitto1.4.5 のインストール方法は、[Invalid protocol "MQTT" in CONNECT の対処方法](http://qiita.com/MahoTakara/items/3637b52d9b7b737d3507) にインストール方法を書いてありますので、参考になると思います。

## JavaScriptプログラムの概要

MQTTのJavaScriptクライアントは、https://eclipse.org/paho/clients/js/で紹介されている Paho JavaScript Client を利用しました。 このURLから JavaScript の MQTTクライアント・ライブラリをダウンロードします。 (http://git.eclipse.org/c/paho/org.eclipse.paho.mqtt.javascript.git/plain/src/mqttws31.js)
このダウンロードした JavaScript のコードは、以下の様に js ディレクトリの下に配置します。このコードは GitHub https://github.com/takara9/iot1 から入手できます。

```lang:/usr/share/nginx/html
iot1
├── index.html　　　計測データ表示ぺージ
└── js
    ├── canvas.js         自作のキャンバス表示コード
    ├── getmsg.js         MQTTイベント処理コード
    ├── jquery.gauge.js   jQueryゲージ
    └── mqttws31.js       MQTTクライアントライブラリ
```

次に計測結果をグラフィカルに解りやすく表示するためのゲージのJavaScriptは、Free jQuery gauge Plugins (http://www.jqueryscript.net/tags.php?/gauge/) の中から、[jQuery Plugin To Draw Animated Gauges using Canvas 2D API] (http://www.jqueryscript.net/other/jQuery-Plugin-To-Draw-Animated-Gauges-using-Canvas-2D-API.html) を選びました。
![スクリーンショット 2016-01-04 0.03.14.png](https://qiita-image-store.s3.amazonaws.com/0/42829/5c86dce3-aacb-cfdc-244a-e7e4e0cfd44c.png)
このプラグインをダウンロードして、jquery.gauge.js を jsディレクトリに配置します。

canvas.js は、出来合いのゲージを使う代わりに、閾値を超えると赤となり、超えない場合緑表示となる信号表示とテキストの数値表示を簡易に作ったものです。

getmsg.jsは、MQTTからのメッセージを受け止めて、ゲージ表示や信号表示の描画パラメータを変更するもので、ブラウザが本ウェブぺージを表示している間、常にMQTTでサブスクライブしたトピックのメッセージを受信待ちをしており、メッセージを受け取ると再描画させます。

index.htmlは、jsディレクトリ以下のJavaScriptのコードを統合して、MQTTで受けたデータをHTML5のキャンバスに、jQueryで書かれたゲージを表示するものです。 このぺージを開くとMQTTブローカーに、WebSocketsで接続して、メッセージを受け取る都度に自動でゲージを更新します。ウェブぺージの再読み込みをすることなく、データを更新していきます。

## MQTTブローカーの設定
Mosquitto 1.4.5では、MQTTとWebSocketsの両方のプロトコルを利用することができます。その設定内容は、以下のように３行を追加するだけです。

```lang:/etc/mosquitto/mosquitto.conf
listener 8080
protocol websockets
http_dir /root
```

## センサー情報トピックをゲージ表示用トピックにPublishするコード

ここで説明するプログラム logger_mqtt.rb は、GitHub https://github.com/takara9/mqtt に置いてありますので、一緒に参照してください。

今回自作したラズパイセンサーは、センサーからの取得情報をJSONテキストで、MQTTブローカーに送信してきます。 

```lang:センサーからのJSONデータ
sensor/pressure,{"sttm": "2016/01/03,21:39:11", "pressure": 1014, "uxtm": 1451824751}
sensor/temp,{"tmp": 25.0, "pin": 4, "mdl": 11, "uxtm": 1451824812, "pos": "desktop", "sttm": "2016/01/03,21:40:12", "erc": 0, "hmd": 32.0}
sensor/temp,{"tmp": 21.0, "pin": 17, "mdl": 11, "uxtm": 1451824812, "pos": "floor", "sttm": "2016/01/03,21:40:12", "erc": 0, "hmd": 36.0}
sensor/temp,{"tmp": 23.0, "pin": 22, "mdl": 11, "uxtm": 1451824813, "pos": "window", "sttm": "2016/01/03,21:40:13", "erc": 0, "hmd": 33.0}
sensor/power,{"sttm": "2016/01/03,21:40:15", "uxtm": 1451824815, "power": 164}
sensor/pressure,{"sttm": "2016/01/03,21:40:15", "pressure": 1014, "uxtm": 1451824815}
```
このデータを時系列でロギングしていけば、長期間のデータとして、季節の移り変わりを分析するなどのデータに利用できます。しかし、ちょっと不便なので、もっと簡単な最新の情報だけを一時保持するキューを作成します。

```lang:ゲージ表示用のキュー
temp_desktop=26.0
humi_desktop=32.0
temp_floor=20.0
humi_floor=37.0
temp_window=24.0
humi_window=33.0
power=42
alert=green
pressure=1015
```

利用するには /usr/local/ で、以下のコマンドを実行してクローンします。

```
root@tkr02:/usr/local# git clone https://github.com/takara9/mqtt
```

## ゲージ表示プログラムのポイント解説
### JavaSctiptのロードと実行開始

HTM5のファイルからMQTT用のJavaScriptのロードします。

```lang:index.htmlの抜粋
<script type="text/javascript" src='js/getmsg.js'></script>
<script type="text/javascript" src='js/mqttws31.js'></script>
```

MQTTブローカーへの接続とコールバック関数設定を設定します。 これはブラウザ上で実行されるので、MQTTブローカーのURLアドレスとポート番号が必須です。　そして、セッションが切れた時のコールバック関数 onConnectionLost を client インスタンスのプロパティ変数に設定します。　それから、メッセージが到着した時のコールバック関数 onMessageArrived を設定します。 これらのコールバック関数は、getmsg.js に書いてあり、リアルタイム表示の中核的な処理です。

```lang:index.htmlの抜粋
<script type="text/javascript">
// Create a client instance
client = new Paho.MQTT.Client("www.mahotakara.wjg.jp", Number(8080), "clientId");

// set callback handlers
client.onConnectionLost = onConnectionLost;
client.onMessageArrived = onMessageArrived;

// connect the client
client.connect({onSuccess:onConnect});
</script>
```
最後に、セッション確立成功時のコールバック関数にonConnectを設定します。これも同様に、getmsg.jsに書いてあります。 MQTTセッションが確立されると、セッションが継続されている間、動作を続けることになります。

### ゲージ描画関数のコールバック

onConnect関数は、受け取り処理するメッセージを設定します。onConnectionLost関数は、セッションクローズを検出した際に、コンソールログにエラーコードを書き出します。

onMessageArrived関数はメッセージが到着するとゲージ描画の関数をコールします。一例として以下のコードは、気圧センサーの値が送られてくると、コールされHTML5のキャンバスに再描画の命令を送ります。

```lang:getmsg.jsの抜粋
function onMessageArrived(message) {
  --- 中略 ---
  if (message.destinationName == "pressure") {
      console.log(message.payloadString);
      $("#gauge1").gauge(Number(message.payloadString), {min: 0, max: 1100, color: "#8BC34A", unit: " HPa", font: "80px verdana"});
  }
```
 
### キャンバスへのゲージの配置
HTML5のウェブページに次の様にゲージを配置する方法を説明していきます。
![スクリーンショット 2016-01-04 9.30.52.png](https://qiita-image-store.s3.amazonaws.com/0/42829/9c942a1e-94b9-64f3-6dd5-d02193252e79.png)
描画にはHTML5から追加されたキャンバスを利用します。 HTML5のキャンバスとJavaScriptのコードを連携させるためのキーワードが idの値 となります。

```lang:index.htmlの抜粋
<table>
<tr>
<td><canvas id="gauge1" width="200" height="200"></canvas></td>
<td><canvas id="gauge2" width="200" height="200"></canvas></td>
</tr>
<tr>
<td><center><font color="white">大気圧</font></center></td>
<td><center><font color="white">消費電力</font></center></td>
</tr>
```
一例に gauge1 の描画について、追っていきます。

メッセージが到着した場合、onMessageArrivedのコードが実行され、気圧データである場合、gauge1 のキャンバスのエリアが再描画されます。

```lang:getmsg.jsの抜粋（再掲）
function onMessageArrived(message) {
  --- 中略 ---
  if (message.destinationName == "pressure") {
      console.log(message.payloadString);
      $("#gauge1").gauge(Number(message.payloadString), {min: 0, max: 1100, color: "#8BC34A", unit: " HPa", font: "80px verdana"});
  }
```

ウェブブラウザ画面の初期状態でゲージ（メーター）描画するのは、index.htmlの中で実施しています。HTML画面の初期描画が完了すると$(document).ready()がコールバックされるので、この中でゲージの初期状態を描画いします。

```lang:index.htmlの抜粋
<script>
$(document).ready(function (){
  $("#gauge1").gauge(1100, {min: 0, max: 1100, color: "#8BC34A", unit: " HPa", font: "80px verdana"});
  ---中略---
});
</script>
```

# まとめ
HTML5を利用することで、JREやFlashなどのプラグインを利用せず、ウェブブラウザでリアルタイムなグラフィックの描画ができることが確認できました。　また、この場合、ブラウザから直接MQTTプロトコルで通信できないので、MQTTブローカー側にWebSocketsの設定が必要であることがも判りました。

最後に、このウェブページの動作は、http://www.mahotakara.wjg.jp/iot1/ で確認できます。