HTTP(S)とMQTT(S)の消費電流とデータサイズを計測する

## tl;dr

- Linux搭載IoT機器がMQTT/MQTTSで通信したときに、HTTP/HTTPSと比べてどの程度消費電流的に有利かを調べてみました。
- 今回の条件でHTTP(S)とMQTT(S)を比較した際、MQTT(S)のほうが消費電流が小さいように見えました。ただし、測定に使用した機器ではベースライン(通信していないとき)の電流が高かったため、HTTP(S)からMQTT(S)にすることで大きな電力的改善は得られませんでした。
    - Linux非搭載のマイコン等の場合、状況が変わると思われます。
    - 通信頻度等にも依存するとは思います。
- HTTP(S)とMQTT(S)の通信データサイズを比較したところ、MQTT(S)のほうが小さいことを確認できました。

## 目的

[MQTT](http://mqtt.org/)はTCP/IP上のプロトコルで、HTTPに比べてヘッダサイズを小さくできシーケンスも単純なため、IoT/M2Mに適したプロトコルだと言われています。
また、ウェブを見ると「電力消費量をHTTPにくらべ低減できる」と記載されているページがあります。ただ、条件によって大きく消費電流は変わりそうなため、自分が使いそうな構成でどの程度消費電流が異なるかを調べてみようと思いました。
ついでにパケットキャプチャを行い、データサイズがどれくらい違うかも見てみようかと。

## 消費電流の計測条件

- 以下のような構成で計測を行いました。ラズベリーパイ等でも似たような計測ができると思います。
- ハードウェア:
  - [LinkIt Smart 7688](https://www.seeedstudio.com/LinkIt-Smart-7688-p-2573.html)
    - 低消費電力のLinux+WiFi搭載ボードのリファレンスとして採用
    - 580MHz MIPS CPU
    - on board Wi-Fi
        - 802.11g / WEP2でWi-Fiルータに接続
- OS:
  - [OpenWRT (Chaos Calmer) Linux](https://openwrt.org/)
  - LinkIt Smart 7688 (2016年12月出荷版)にプリインストールされているOSを使用
- アプリ
  - node.jsで書いたテストプログラムを使用


## 消費電流の計測回路

以下のようなケーブルを作成しました。電源供給用のUSBケーブルの電源ラインに0.47Ωの抵抗を挿入しています。その両端の電圧を測ることにより、流れる電流を計算します。

![IMG_0214.JPG](https://qiita-image-store.s3.amazonaws.com/0/42108/a8e34bf5-15bf-3cc4-3f48-07bb78a4a437.jpeg)

KOAさんの[電流検出抵抗器の使い方](http://www.koaglobal.com/product/howtouse/currentsense)というページが参考になります。
オシロスコープは[DSO Nano v3](https://www.seeedstudio.com/DSO-Nano-v3-p-1358.html)が手元にあったので、これを使用しました。

## HTTP/HTTPSのデータを送信するコードの準備

### デバイス側

以下のようなnode.jsのコードで、サーバにHTTPのPOSTを行ってみます。POSTのデータとしてjsonで1要素だけ入れています。センサからデータを投げるときは最低限これくらいのサイズかな、と想像しています。同じデータを10回送信し、その平均をとる作戦です。

```js
var http = require('http');

var postData = {
    "data": "hoge",
};
var postDataStr = JSON.stringify(postData);
var options = {
    host: 'hogehoge.com',
    port: 80,
    path: '/',
    method: 'POST',
};

var count = 0;
var timer = setInterval(function() {
    var req = http.request(options, function(res) {
    });
    req.write(postDataStr);
    req.end();
    count += 1;
    if (count >= 10) {
        clearInterval(timer);
    }
}, 1000);
```

HTTPSもほぼ同様での内容で、`http`の代わりに`https`モジュールを使用している感じです。

```js
'use strict';

var https = require('https');

var postData = {
    "data": "hoge",
};
var postDataStr = JSON.stringify(postData);
var options = {
    host: 'hogehoge.com',
    port: 443,
    path: '/',
    method: 'POST',
    rejectUnauthorized: false,
};

var count = 0;
var timer = setInterval(function() {
    var req = https.request(options, function(res) {
    });
    req.write(postDataStr);
    req.end();
    count += 1;
    if (count >= 10) {
        clearInterval(timer);
    }
}, 1000);
```

### サーバ側

サーバ側はこんな感じで、ステータスコードだけを返すようにしています。サーバはAWS EC2上に置きました。

HTTPはこれ。

```js
const http = require('http');

const server = http.createServer((req, res) => {
    if (req.url === '/' && req.method === 'POST') {
        res.writeHead(200);
        res.end();
    }
});

server.listen(80);
```

HTTPSはこちら。証明書は事前に作成しておきます。

```js
var https = require('https');
var fs = require('fs');

var SECURE_KEY = 'key.pem';
var SECURE_CERT = 'cert.pem';
var options = {
    key: fs.readFileSync(SECURE_KEY),
    cert: fs.readFileSync(SECURE_CERT)
};

const server = https.createServer(options, function (req, res) {
    if (req.url === '/' && req.method === 'POST') {
        res.writeHead(200);
        res.end();
    }
});

server.listen(443);
```

## MQTT/MQTTのデータを送信するコードの準備

### デバイス側

MQTTのコードは以下のようにしました。今回はセンサから定期的にサーバにデータを送信することを想定し、pub/subのうちpublishのみを実装し、subscribeは行いません。

MQTTはこのような感じです。

```js
var mqtt = require('mqtt');
var client  = mqtt.connect('mqtt:hogehoge.com');

var count = 0;
client.on('connect', function () {
    var timer = setInterval(function() {
        client.publish('sensor', 'hoge');
        count += 1;
        if (count >= 10) {
            clearInterval(timer);
            client.end();
        }
    }, 1000);
});
```

MQTTSはこちら。

```js
var mqtt = require('mqtt');
var fs = require('fs');
var path = require('path');
var SECURE_KEY = 'key.pem';
var SECURE_CERT = 'cert.pem';
var options = {
    protocol: "mqtts",
    port: 8883,
    host: "hogehoge.com",
    keyPath: SECURE_KEY,
    certPath: SECURE_CERT,
    rejectUnauthorized: false,
};

var client = mqtt.connect(options);

var count = 0;
client.on('connect', function () {
    var timer = setInterval(function() {
        client.publish('sensor', 'hoge');
        count += 1;
        if (count >= 10) {
            clearInterval(timer);
            client.end();
        }
    }, 1000);
});
```

MQTTのbrokerは[mosca](https://github.com/mcollina/mosca)を使用しました。このような感じです。

MQTT用:

```js
const mosca = require('mosca');
const moscaSettings = {
    port: 1883,
};
const server = new mosca.Server(moscaSettings);

server.on('ready', setup);

server.on('published', (packet, client) => {
    console.log('Published', packet.payload);
});

function setup() {
    console.log('Mosca server is up and running');
}
```

MQTTS用:

```js
const mosca = require('mosca');
var SECURE_KEY = 'key.pem';
var SECURE_CERT = 'cert.pem';
const settings = {
    secure : {
        port: 8883,
        keyPath: SECURE_KEY,
        certPath: SECURE_CERT,
    }
};
const server = new mosca.Server(settings);

server.on('ready', setup);

server.on('published', (packet, client) => {
    console.log('Published', packet.payload);
});

function setup() {
    console.log('Mosca server is up and running');
}

```

## 消費電力どうだったか

### 通信時の電流まとめ

大体以下のようなかんじになりました。
(＊試行数やサンプリングレートが十分ではないので、概算結果となります)

| プロトコル   |初回       |それ以外    |
|:----------|:---------|:----------|
| 非通信時   |--        | 常時170mA      |
| HTTP      |64mA * 80msec |64mA * 6msec |
| HTTPS     |64mA * 80msec |64mA * (5~30msec) |
| MQTT      |64mA * 70msec |0に近い      |
| MQTTS     |64mA * 70msec |0に近い      |

以下、詳細です。

### まずは通信していないときの消費電流を計測する

通信していないタイミングでは、オシロスコープで計測される電流は約80mVで安定していました。抵抗は0.47Ωのため、流れる電流は `80mV / 0.47Ohm = 170mA`となります。

<img width="400" alt="ss.png" src="https://qiita-image-store.s3.amazonaws.com/0/42108/feedbf6a-d5be-0c8e-cd69-24b0db566ede.png">

### HTTP通信しているときの消費電流を計測する

![http.gif](https://qiita-image-store.s3.amazonaws.com/0/42108/69517b14-ba74-2695-297c-a674316f86d3.gif)

通信しているときに`6msec * 30mV`程度の電圧変化がありました。30mVは電流換算で`30mV / 0.47Ohm = 64mA`となります。
また、通信初回は`30mV*80msec`程度の電圧変化がありました。

<img width="851" alt="スクリーンショット 2017-02-26 21.01.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/42108/8ca22c84-fc43-3c30-1df5-ffbd9cf67e42.png">

### MQTT通信しているときの消費電力を計測する

![mqtt.gif](https://qiita-image-store.s3.amazonaws.com/0/42108/cd51c358-76b2-ec85-577d-0d924d6a7707.gif)

MQTT通信の開始(connect)時に比較的長時間(40msec程度)電流が流れる時間があるものの、HTTP時のような電流変化は見られませんでした。(もう少しオシロスコープのサンプリングレート等を調整すれば見えるかも)

### HTTPS通信をしているときの消費電力を計測する

![https.gif](https://qiita-image-store.s3.amazonaws.com/0/42108/d1a300af-6f6a-a392-c10b-0774ec862c18.gif)

HTTP通信と同様通信しているときに`30mV`程度の電圧変化がありました。電圧が上がっている期間は様々なようにみえます(5msec程度のときもあれば30msec以上のケースもありそう)。

### MQTTS通信しているときの消費電力を計測する。

![mqtts.gif](https://qiita-image-store.s3.amazonaws.com/0/42108/f8b7beb9-4b11-f13b-45bd-0537617a165a.gif)

MQTT通信と同様初回に`30mV * 70msec`程度の電圧変化があるものの、それ以降は5msec程度の電圧上昇がみられたり見られなかったりという感じでした。

## 通信データサイズどうだったか

ちなみに、1リクエストの通信データサイズはこんな感じでした。３−way handshake等の通信がない分・ヘッダ等が小さい分、MQTTのほうがデータサイズが小さくなっていることがわかります。

| プロトコル   |サイズ(TCP/HTTP往復合計)(byte)    |
|:----------|:----------|
| HTTP      |981 |
| HTTPS     |2059|
| MQTT      |146 |
| MQTTS     |291 |

### HTTP

<img width="1106" alt="cap_http.png" src="https://qiita-image-store.s3.amazonaws.com/0/42108/f1148b4a-9ef1-324f-dbcd-026978d6c661.png">

### HTTPS

<img width="1104" alt="cap_https.png" src="https://qiita-image-store.s3.amazonaws.com/0/42108/080cf300-6623-d4c4-20c9-23fc13e3feba.png">

### MQTT

<img width="1105" alt="cap_mqtt.png" src="https://qiita-image-store.s3.amazonaws.com/0/42108/1f8e992a-285d-08fd-6d42-889cd87c999c.png">

### MQTTS

<img width="1105" alt="cap_mqtts.png" src="https://qiita-image-store.s3.amazonaws.com/0/42108/766eb786-7fad-8521-8b2d-8a23a84629fb.png">

## まとめ

- 今回の条件でHTTP(S)とMQTT(S)を比較した際、MQTT(S)のほうが消費電流が小さいように見えました。
- ただし、測定に使用した機器ではベースライン(通信していないとき)の電流が高かったため、HTTP(S)からMQTT(S)にすることで大きな電力的改善は得られませんでした。
- HTTP(S)とMQTT(S)の通信データサイズを比較したところ、MQTT(S)のほうが小さいことを確認できました。
- もう少し丁寧に消費電流を計測したいところ。。
- ESP8266等のWi-Fi機能付きマイコンでも似たような調査を今後行いたいと思いました。