Espruino - MQTT のpublisherとして動かす

少し前に[KickStarter](https://www.kickstarter.com/projects/gfw/espruino-pico-javascript-on-a-usb-stick)でEspruinoの超絶小型版である **Espruino Pico** が登場して話題になりましたが、実はそのとき同時に「金額が一定額に達したら **[MQTT](https://sango.shiguredo.jp/mqtt)対応する** 」とのアナウンスもされておりました。

その後見事に目標金額を達成したようで、EspruinoのMQTT対応が決定したらしいです。とあるトイレのドアの空き状況を超絶不安定なWifi/CC3000の上でひたすらpostリクエスト使って投げ続けてきた僕にとっては、まさに待ち望んだアップデートであったために、これは春まで待ちきれない！という具合にテンションが上がっていた訳です。

で、Espruinoの公式フォーラム見ていたら、なんとPICOのリリースに先駆けて「[MQTTはもう使えるようにし始めてるよ](http://forum.espruino.com/conversations/258515/#comment11954062)」なんて言っているのを見つけたのでさっそく試してみました。（記事としては11月なんですがね）

# 目標

* MQTTでコタツの温度をサーバ(subscriber)に送りつけます。
* [MQTT](https://sango.shiguredo.jp/mqtt)についての解説はここでは省略します。
* [17日目](http://qiita.com/rockymanobi/items/e85a57408fa07da6b29c)に引き続き、コタツばっかりですみません。

![image](https://qiita-image-store.s3.amazonaws.com/0/51384/edad78b4-51d4-1c04-9b4f-598401424b60.png)

# 流れ

1. パーツの調達と結線
2. Espruinoのファームウェアをアップデート
3. MQTTのbroker / subscriber を用意
4. 実行

# パーツの調達と結線

必要物品は以下。[15日目の記事](http://qiita.com/rockymanobi/items/1dd62833b4c055a71460)及び[5日目の記事](http://qiita.com/rockymanobi/items/6e1dad4ffb1644b60b51)を参考に調達及び結線します。

* Espruino
* CC3000Wifiモジュール
* 温度センサ

# Espruinoのファームウェアをアップデート

通常のファームウェアアップデートで使えるバージョンではMQTTを使えない（2014/12/21時点)ので、最新版のバイナリのURLを指定する方法でファームウェアをアップデートします。

`WebIDEの設定画面 > Flusher > Advanced Firmeware Update`の下にあるテキストインプットに下記URLを入力してAdvanced Flush Firmwareボタンをクリックします。その後は通常のファームウェアアップデートと同手順です。([2日目の記事](http://qiita.com/rockymanobi/items/bbc9481d43cd4fc19d65)を参照)

```
http://www.espruino.com/binaries/git/commits/1f5e0ac3cd62ff9328e3c38a03f07d7644fff3e8/espruino_1v72_espruino_1r3.bin
```

![image](https://qiita-image-store.s3.amazonaws.com/0/51384/f1280c2d-6f15-37f0-0dca-64f822bc9667.png)




# MQTT Broker/subscriber の準備

Espruinoメインとはいえ、MQTTのサーバ(broker)と、本当に動いているかどうかを確かめるためにsubscriberが必要です。[MQTT.js](https://github.com/adamvr/MQTT.js/)を利用した`broker`と`subscriber`をGithubのリポジトリに置いたのでそれを使いましょう。中身はExampleのsubscriberとbroadcast serverを参考に書いています。

以下、`node.js`,`npm`がインストールされた環境での手順を記載します。

```bash
git clone https://github.com/rockymanobi/espruino-mqtt-sample.git
cd espruino-mqtt-sample
npm install
```
ターミナル2画面で以下コマンドをそれぞれ実行します。

brokerの実行

```bash
node broker.js
```

subscriberの実行

```bash
node subscriber.js
```
![image](https://qiita-image-store.s3.amazonaws.com/0/51384/2f1f5f7a-0cb3-cf0a-48cc-3cabc8ae3cca.png)

こんな風になっていれば準備完了です。`Ctrl + c`で終了する事ができます。

試しに`node publisher.js`を実行すると`subscriber.js`を実行しているウィンドウに何か出てくるので、それで疎通確認をしても良いと思います。

# プログラム

下記プログラムの`var config`の値を、実行する環境に合わせて編集した後に実行します。ちなみに`mqttHost`には`localhost`よりも、IPアドレス(`broker.js`実行時に表示されます)を指定した方が良いです（Espruino、たまにlocalhost接続だとwifiモジュールが落ちたりするので）

```js
var config = {
  wifiSSID: 'ssid',
  wifiKey: 'password',
  mqttHost: '192.168.xxx.xxx',
  mqttPort: '1883',
};

function mtStr(s) {
  return String.fromCharCode(s.length>>8,s.length&255)+s;
} function mtPacket(cmd, variable, payload) {
  return String.fromCharCode(cmd, variable.length+payload.length)+variable+payload;
}
function mtpConnect(name) {
  return mtPacket(0b00010000, 
           mtStr("MQTT")/*protocol name*/+
           "\x04"/*protocol level*/+
           "\x00"/*connect flag*/+
           "\xFF\xFF"/*Keepalive*/, mtStr(name));
}
function mtpPub(topic, data) {
  return  mtPacket(0b00110001, mtStr(topic), data);
}

var client;
function onConnected() {
  console.log('creating client');
  client = require("net").connect({host : config.mqttHost , port:config.mqttPort}, function() {
    console.log('client connected');
    client.write(mtpConnect("Espruino"));

    setWatch(function() {
      var temperature = sensor.getTemp();
      console.log("Publishing " + temperature );
      client.write(mtpPub("message", temperature. toFixed(4)));
    }, BTN1, { repeat:true, edge: 'falling' } );

    client.on('end', function() {
      console.log('client disconnected');
    });
  });
}



var wlan,sensor, ow;
// main
function main(){ 
  // Setup Temperature Sensor
  ow = new OneWire(A1);
  sensor = require("DS18B20").connect(ow);
  sensor.getTemp();
  // WIFI
  wlan = require("CC3000").connect();
  wlan.connect( config.wifiSSID , config.wifiKey, function (s) { 
    if (s=="dhcp") {
      console.log("My IP is "+wlan.getIP().ip);
      onConnected();
    }
  });
}

main();

```

基本的には[フォーラムのサンプル](http://forum.espruino.com/conversations/258515/#comment11954062)のままですが、[最新ビルド]()にアップデートしたEspruinoで(espruino_1v72_espruino_1r3.bin)でなぜか`setInterval`,`setTimeout`がうまく動作しなかったので`setWatch`を使い、`BTN1`を押したタイミングで温度をMQTTで送信するようにしました。

# 実行

Espruinoの接続設定が、broker/sbscriberが動いているPCが同じネットワークであることを確認しつつ、プログラムを実行します。

実行時に`net`なんてモジュールは無いと言われますが普通に動きます。
![image](https://qiita-image-store.s3.amazonaws.com/0/51384/f343c248-cdb8-9037-796e-0ac8f433d22c.png)

**画像**![image](https://qiita-image-store.s3.amazonaws.com/0/51384/9c8c7c59-e8ef-5f4d-e770-bff8b20b4dba.png)

ボタンを押すたびに、EspruinoからMQTTで送信した温度が、subscriberのコンソールに表示されています。どうやら成功のようです。暖かそうですね。

# まとめ

フォーラムの文章にもある通り、単純すぎるサンプルでもあるのでこのまま使える代物では無いですが、とりあえず、MQTTデキソウダ！と思える感じには動かすことに成功しました。今後は接続喪失時の再接続とか、耐久性とか、いろいろ試していけたらと思います。