SORACOM Beamによる通信量の削減効果を金額と電力量の数値で示す

2019/12/17 Wio LTEの消費電力比較を追記しました！[こちら](#wio-lteの消費電力測定)からご覧いただけます。

#はじめに

IoTプラットフォームを提供するSORACOMに最初からあったサービスは２つ。
１つはコンソールやWebAPIで携帯回線を自由にコントロールできるSORACOM Air、
もう１つはデバイスからソラコムはSIMで認証された安全なネットワークで通信し、ソラコムで安全なプロトコルに変換して外部にアクセスするSORACOM Beamです。

両方素晴らしいのですが、僕は特にSORACOM Beamに感銘を受けました。
https://soracom.jp/services/beam/
SORACOM Beamでは以下を実現することができます。

- 軽量な平文通信を暗号通信に変換
- 通信先をクラウド側で設定可能
- SIMで認証された認証情報をクラウドで付与

これは、安全なキャリア網とインターネットを接続するポジションにいる通信会社だからこそできるサービスです。

通信サービスの提供と言った場合、通常はカバー率や安定した速度、安さなどを売りにします。土管屋などと言われてはいますが、それはそれで大事なことです。ですがSORACOM Beamでは従来無かった方法で通信に付加価値を与えることができており、しかもそれは価格、電力などの面で制約の大きいデバイスを安全に通信させるというIoTの用途にマッチしています。こんなやり方があったのかと感心したものです。

これらの機能によってデバイスは

- 暗号化や検証などの高負荷な処理をしなくてもよい
- サーバー、クライアント証明書のやりとりなどのオーバーヘッドの大きな通信をしなくてよい
- 認証情報を保存、送信しなくても良い

といった恩恵を受けます。この結果通信量を大幅に削減することができます。（他にも色々な効果がありますがそれは後日のネタにします）通信量が削減されると何が良いのでしょうか？

まず当然ですが通信料金を下げることができます。特にIoT SIM(グローバルSIM)の場合、通信量を下げる努力はされているもののローミングであるため通信量単価は高く、例えば日本では\$0.20/MBです。（¥じゃ無いですよ）月に1GB通信するとしたら\$200かかり、ランニングコストがとても高くなりますね。

Beamの価格は1リクエストあたり\$0.000009、実際はデバイス-ソラコム間とソラコム-サーバー間の２回発生するので\$0.000018です。これは90byte分の通信量にあたるので、Beamを使うことにより90byte通信量が削減できればBeamを使った方がコスト的に有利です。あとで実測しますが、このくらいの削減は余裕です。

このように、通信料単価が高いグローバルでの通信においてBeamなどによる通信量の削減はほぼ必須であり、逆にこれができるところにソラコムの強みがあります。

また通信量が下げられると、電波を送信している時間が下げられるため、消費電力を小さくすることが出来ると期待できます。消費電力は特にバッテリーや乾電池、コイン電池などで動作するデバイスの動作時間を決定する要素で、文字通り死活問題ですね。電池駆動機器のハードウェア・ファームウェア担当は1μAでも消費電力を落とせるよう日々鎬を削っています。SORACOM Beamでの通信量削減が消費電力低減につながれば面白いですね。

それでは、どの程度通信量が削減できるのかを検証していきましょう

# 通信量の計測方法

計測にはtcpdumpによるパケットキャプチャを用いて、パケットサイズを合計することとします。
計測環境としてはRaspberry Pi 3 Model B+を用います。手元にあるからです。ラズパイ４欲しい。
たとえばSORACOM Air メタデータサービスからの情報取得の場合、

`sudo tcpdump -i ppp0 -w metadata.pcap`
としてキャプチャを仕掛けた上で、
`curl http://metadata.soracom.io/v1/subscriber`
とすると、

```bash
pi@raspberrypi:~ $ sudo tcpdump -i ppp0 -w metadata.pcap
tcpdump: listening on ppp0, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
^C14 packets captured
14 packets received by filter
0 packets dropped by kernel
```

こんな感じで取得されます。14パケット。。結構多いですね。0 packets dropped by kernel、となっているので、取りこぼしもなさそうです。

保存されたmetadata.pcapをWiresharkで確認するとこんな感じです。

![スクリーンショット 2019-12-14 6.00.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/54a17c2a-3355-150f-c14d-94d4a9f2d519.png)

あ、DNSが入っちゃってますね。しかも何回やってもDNSされる。うーむ、どうやら初期状態のRaspberry Pi(というかLinuxでは割と一般的に？)ではDNSキャッシュはしないみたいです。ある意味実動作に近いのですが、今回はDNS部分を無くして算出するため、dnsmasqをインストールしてキャッシュしておきます。こういうの地味な積み重ねが通信量削減に効くのですね。

では改めて取得します。DNSがなければ10パケットになってるはず。結果はこんな感じで、きれいに取れました。

![スクリーンショット 2019-12-14 7.00.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/46a9839a-13d0-f045-f1f5-bde0d5151bd8.png)

ひとつのパケットは、

1. L2(???)
2. L3(IPヘッダ)
3. L4(TCP/UDPヘッダ)
4. L5-7(ペイロード)

で構成されています。Ｌ２を???としたのは、LinuxのtcpdumpだとL2がPPPのはずがLinux cooked captureになってしまいちゃんと取得されていない(https://wiki.wireshark.org/SLL 参照)ということと、そもそもソラコムに届いている時点でL2がどうなってるかは不明であるためです。（どなたかソラコムではL2の長さをどう計算しているかご存じですか？）今回はやや不正確にはなりますが、L2はLinux cooked caputerの16byteとします。

IPヘッダはIPv4なので20byte+オプション、TCPヘッダは20byte+オプション、UDPヘッダは8byteです。ということは例え中身の無いTCPパケットでも最低56byteは使っているということですね。このキャプチャを見る限り、最低は68byteのようです。

通信全体を見ると、

1. 3wayハンドシェイク部(76 + 76 + 68 = 220byte)
2. HTTP部(164 + 68 + 1008 + 68 = 1308byte)
3. 通信終了部(68 + 68 + 68 = 204byte)

で合計1732byteとなります。さらにHTTPの中にはリクエストヘッダ(96byte)とレスポンスヘッダ(143byte)があり、ペイロードであるメタデータは797byteです。センサーデータなどと比べると大きめのペイロードですが、それでもヘッダや通信開始、終了などのオーバーヘッドが半分以上ということがわかりますね。極端な話1byteのデータ１個アップロード、みたいな場合でも、同じだけのオーバーヘッドは発生します。

では計測方法も決まったところで、実際の計測に進みます。

# 通信量削減の計測

状況として以下のJSONファイル(温度を12点測定してタイムスタンプつきでアップロードする適当なJSON。200byte)をAWS S3にアップロードする状況を想定し、以下の５種類で通信量を計測、比較します。

```json
{"temp1":17.89,"temp2":-23.64,"temp3":0.92,"temp4":39.51,"temp5":33.07,"temp6":46.43,"temp7":-15.19,"temp8":16.37,"temp9":-46.8,"temp10":-42.97,"temp11":-16.76,"temp12":47.8,"timestamp":1576276812744}
```

1. デバイスから直接AWS CLIでアップロードする
2. HTTPエントリポイントでアップロードする
3. TCP → HTTPSエントリポイントでアップロードする
4. UDP → HTTPSエントリポイントでアップロードする
5. UDP → HTTPSエントリポイントでバイナリパーサーを使ってアップロードする

では早速行きましょう。

### 1. デバイスから直接AWS CLIでアップロードする

サーバーやPCからでは普通に行われているこの操作にどれくらい通信量がかかっているでしょうか？

```json
pi@raspberrypi:~ $ aws s3 cp traffic.json s3://traffic-amount/traffic.json
upload: ./traffic.json to s3://traffic-amount/traffic.json 
```

39個のパケットがキャプチャされました。中を見てみましょう。
![スクリーンショット 2019-12-14 8.04.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/1e824487-c6d3-0221-4732-79de03ddd427.png)

またDNSが入ってしまった。S3バケットのレコードはキャッシュできないのかな。。とりあえずこれは手動で除外しておきます。また、再送とその影響も出ていますね。(No4、7、8)今回はこれも除外しておきます。現実にはこういうのが積み重なって、割と馬鹿にならない通信が発生しているのかも知れません。

これらを除外した合計は**7301byte**です。\$0.20/1MB換算で\$0.00139(約¥0.153)

ペイロード200byte(2.74%)でオーバーヘッドが7101byte(**97.26%**)。特に目を引くのがやはりNo.9〜30までのTLSハンドシェイク。これだけで5332byte(73.03%)あります。よく見るとNo17のCertificate(サーバー証明書の取得)はNo.13とNo.15と合わせて３分割されており、3304byteかかっていますね。TLSハンドシェイクのオーバーヘッドは大きいと聞いていたがこれほどとは。。これがなくなるだけで通信量を格段に落とせる予感がひしひしとしますね。だって73%ですよ？

また、No.31のApplication Data(暗号化されている)は認証かな？中身見られないのでわかりませんが。Beamの認証情報でデバイス認証を代行すれば、ここも削減できそうですね。

あとは除外してしまったけどインターネットを通らないBeamに送ることでTCP再送が起こりにくくなる効果もあるかも。これは評価が難しいところですが。

それではまずこのTLSハンドシェイクを無くしましょう。HTTPエントリポイントです。

### 2. HTTPエントリポイントでアップロードする

HTTPエントリポイントはBeamが受け取った平文のHTTPをHTTPSに変換して、指定したエンドポイントに中継してくれる機能です。ソラコムのネットワークを安全な大きなLANと考えると、LANの中にあるプロキシと考えてそれほど間違いでは無いと思います。

まずS3をアップロードさせるためのエンドポイントを用意しなければなりません。まあFunnel→Kinesis→S3でもいいのですが、Beamでやると書いてしまったのでBeamでやります。簡単な構成としてはBeam → API Gateway → Lambdaですかね。今回はここが本題ではないので準備部分は飛ばして、https://XXXXXXXXXX.execute-api.ap-northeast-1.amazonaws.com/v0 にPOSTしたらS3に保存されるようにしました。

BeamのHTTPエンドポイントを設定します。
![スクリーンショット 2019-12-14 9.23.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/3c8ccc4e-52b8-fc98-b1d5-003d216a17be.png)

![スクリーンショット 2019-12-14 9.26.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/d6153760-fba9-9b54-baef-eba1e42b90c9.png)

設定は見たままなのですが、Beamの署名ヘッダをONにしておくのがお勧めです。これをやっておくとデバイスの認証や認証トークンの送信といった部分の通信量を削減できます。（もちろんデバイスに認証情報を持たなくて良いという大きなメリットもあります。これについては後日５回シリーズくらいでやりたい）

それでは実行してみましょう！
`curl -H "Content-Type: application/json" -d '{ペイロード200byte}' http://beam.soracom.io:8888/`
OKが返ってきました。パケット数は10!良い感じです。

```bash
pi@raspberrypi:~ $ sudo tcpdump -i ppp0 -w beam-http.pcap
tcpdump: listening on ppp0, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
^C10 packets captured
10 packets received by filter
0 packets dropped by kernel
```

パケットキャプチャ結果は、、

![スクリーンショット 2019-12-14 9.42.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/e2b6c0d5-3dc1-2c1d-f084-edfecee9751c.png)

合計は**1518byte**、\$0.20/1MB換算で\$0.000290(約¥0.0318)、1.からの削減率はなんと**79.2%!**
いきなりすごい効果出ちゃいましたね。そりゃそうだ、さっきのTLSハンドシェイク5332byteが全部無くなったんだから。

ちょっと気になるのはNo.6の"OK"しか返していないはずのHTTPレスポンスが552byteとやけに大きいこと。中を見るとAPI Gatewayからのレスポンスヘッダがいっぱい入ってるようです。こういうサーバーがデバイスでは使わない情報を付加してくるのが通信量削減の課題になります。次はここが大きなオーバーヘッドですね。

それはどうにかなるのか？といえばなるんですね。それでは次のTCP→HTTPSエントリポイントに進みましょう。

### 3. TCP → HTTPSエントリポイントでアップロードする

TCP → HTTPSエントリポイントはTCPで送信した内容をペイロードとして、指定したHTTPSエンドポイントに対してPOSTメソッドでアクセスしてくれる機能です。

BeamでTCP → HTTPSエントリポイントを設定しましょう。

![スクリーンショット 2019-12-14 10.02.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/e594d227-8c45-6c35-54a7-a7df94e668ac.png)

設定項目は先ほどとほぼ同じですので省略します。「ステータスコードを省略」の項目はとりあえずOFFにしました。
それでは実行してみましょう。

```bash
pi@raspberrypi:~ $ nc beam.soracom.io 23080
{ペイロード200byte}
200 "OK"
```

キャプチャしたパケット数は先ほどと同じ10パケット。内容を見ると、
![スクリーンショット 2019-12-14 10.20.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/e33c8c46-90b4-cf4c-3382-e0b89325d4f6.png)

素晴らしく「単なるTCP通信」ですね。HTTPヘッダのような余計なものが入っていない。No.6に先ほど残したステータスコードとスペース(200 )が入っているのですが、まあこの程度は許容できるでしょう。

合計は**906byte**、\$0.20/1MB換算で\$0.000173(約¥0.0190)、1.からの削減率は**87.6%**
1kBを切りました。ペイロード率も22.1%とかなり向上しています。(1.では2.74%)

しかしこれ以上なにかできるんでしょうか。この中で意味のあるパケットはNo.4のデータ送信(269byte)とNo.6(77byte)の応答だけなのですが、TCPである以上は3wayハンドシェイクやACK(合計560byte)を省くことはできません。。ん？TCPである以上は？

ということで次はUDP→HTTPSエントリポイントに行ってみましょう！

### 4. UDP → HTTPSエントリポイントでアップロードする

UDP → HTTPSエントリポイントはUDPで送信した内容をペイロードとして、指定したHTTPSエンドポイントに対してPOSTメソッドでアクセスしてくれる機能です。TCPと違い、3wayハンドシェイクもありませんし、ACK応答もありません。またヘッダサイズがわずか8byteとTCPの最低20byte(ここまでのキャプチャ結果を見ると32byteか40byteになることが多い)に比べ格段に小さいです。これは期待できそうですよ！

それではBeamのUDP→HTTPSエントリポイントの設定をしましょう。一番下にあります。最強感が出てて良いですね。
![スクリーンショット 2019-12-14 10.35.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/b7430584-1e77-2b33-3876-cc431638cce9.png)

設定項目は先ほどとほぼ同じですので省略します。今度は「ステータスコードを省略」の項目をONにしてみました。

それでは実行してみましょう。

```bash
pi@raspberrypi:~ $ nc -u beam.soracom.io 23080
{ペイロード200byte}
"OK"
```

キャプチャしたパケット数は、、、

```bash
pi@raspberrypi:~ $ sudo tcpdump -i ppp0 -w beam-udp.pcap
tcpdump: listening on ppp0, link-type LINUX_SLL (Linux cooked), capture size 262144 bytes
^C2 packets captured
2 packets received by filter
0 packets dropped by kernel
```

**２個!**。鳥肌立ってきましたね。パケットの内容は、

![スクリーンショット 2019-12-14 10.45.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/9ceb05ef-f2a5-7f13-3c68-25d5376de758.png)

データの送信とその応答しかない！理想的です。しかもこれ対サーバーに対してはちゃんと認証付きのTLS通信されてますからね。
合計は**293byte**、\$0.20/1MB換算で\$0.0000559(約¥0.00615)、1.からの削減率は**96.0%**

ただしこれは諸刃の剣ではあります。TCPまではまあ信頼性には影響を与えない構成だったのですが、UDPを使うと送達確認はアプリ側でやらなければなりません。逆にいえばそれが許容できるのであれば、UDP→HTTPSは通信量削減の強力な武器になります。

さて、そろそろここが限界ですかね。さすがにもうなんともならんやろ。パケットはもう2個しかないし、残っているのは必須のヘッダとペイロードだけだし、ペイロードに手をつけるわけには。。って思うじゃないですか。でもまだ最後の一手があるんです。それが**バイナリパーサー**です。

### 5. UDP → HTTPSエントリポイントでバイナリパーサーを使ってアップロードする

バイナリパーサー(https://dev.soracom.io/jp/docs/binary_parser/ )は
> バイナリパーサーとは SORACOM Air でご利用いただけるバイナリデータをJSONデータに変換する機能です。

という機能です。要はペイロードがJSONフォーマットというサイズ大きめのフォーマットになっているのが問題で、同じ意味のバイナリであればもっと小さく出来ます。でもサーバー側でバイナリを直接扱うのはやっかいで、サーバー側としてはJSONで受け取りたいです。そこでその中間にいるソラコムが、バイナリをデバイスから受け取って、JSONに変換してサーバーに送ってくれる、という機能です。

それでは試してみましょう。バイナリパーサーはAirの設定にあります。

![スクリーンショット 2019-12-14 11.44.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/b0c8bc5c-b540-7238-4660-b37edebcd707.png)
この「フォーマット」という欄にバイナリパーサーの指定を書いていくのですが、正直ここはちょっと難しいです。
開発者サイトの記載(https://dev.soracom.io/jp/docs/binary_parser/ )と、
実験できるページ(https://binary-parser-playground.soracom.io/ )をもとに、
試しながら作成しました。

例えば"temp1":17.89の部分は17.89は小数なのですが、固定小数としてあつかっているので2byte(16bit)の整数としてパースして1/100するようにしており、その指定がtemp1:0:int:16:/100です。そのように各温度とタイムスタンプをパースする設定を作ります。これにより、JSONテキストでは200byteだったペイロードを32byteにまで削減する事が出来ました。ただし、タイムスタンプが64bit整数なのですが、バイナリパーサーが対応しているbitが32までだったため、timestamp_highとtimestamp_lowに分割しています。

さて実測です。ncコマンドでバイナリを送る方法が分からなかったので、適当なrubyコードを作って送るようにします。

```ruby
pi@raspberrypi:~ $ cat udp_send.rb 
require 'socket'
require 'timeout'
binary = [1789, -2364, 92, 3951, 3307, 4643, -1519, 1637, -468, -4297, -1676, 478].pack('n12') + [1576276812744].pack('Q')
udp = UDPSocket.open()
sockaddr = Socket.pack_sockaddr_in(23080, 'beam.soracom.io')
udp.send(binary, 0, sockaddr)

Timeout.timeout(5) do
  udp_recv = udp.recv(4096)
  p udp_recv
end
udp.close
pi@raspberrypi:~ $ ruby udp_send.rb
"\"OK\""
```

OK応答があり、lambdaにもバイナリ化前と同じbodyが入ってくるのを確認しました。(CloudWatchLogsのログの抜粋)

```json
"body": "{\"temp1\":17.89,\"temp2\":-23.64,\"temp3\":0.92,\"temp4\":39.51,\"temp5\":33.07,\"temp6\":46.43,\"temp7\":-15.19,\"temp8\":16.37,\"temp9\":-4.68,\"temp10\":-42.97,\"temp11\":-16.76,\"temp12\":4.78,\"timestamp_high\":367,\"timestamp_low\":23815112}"
```

そしてパケットの内容
![スクリーンショット 2019-12-14 12.13.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/0f0f4686-114f-ae4a-3477-f210d4e40290.png)

送信のペイロードは32byteになりました。なにかもはや寂しささえ感じますね。
合計は**124byte**、\$0.20/1MB換算で\$0.0000237(約¥0.00260)、1.からの削減率は**98.1%**
ということになりました。

ソラコムのサービスを駆使すれば、IoTの通信量は1/50程度にまで下げる事ができる、ということは言えそうですね。
とりあえず僕の理解ではここまでが限界です。他の技があったら教えてください。

# 通信量、通信料金削減の結果

通信量削減の結果をまとめます。コスト計算は、\$0.20/1MB、\$1 = ¥110、ひと月は31日、5分に１回200byteのデータをS3などのクラウドサービスに送信するというケースで計算しています。この場合、Beamの使用料金は¥17.7程度です。

|方法|１回あたりの通信量|1回あたりの料金|月あたりの通信量|月あたりの料金|削減率|
|:--|--:|--:|--:|--:|--:|
|直接CLI|7301byte|¥0.153|62.2MB|¥1367|0%|
|HTTPエントリ|1518byte|¥0.0318|12.9MB|¥284.3|79.2%|
|TCP → HTTPSエントリ|906byte|¥0.0190|7.71MB|¥169.7|87.6%|
|UDP → HTTPSエントリ|293byte|¥0.00615|2.49MB|¥54.88|96.0%|
|UDP + バイナリパーサー|124byte|¥0.00260|1.06MB|¥23.23|98.1%|

IoT SIM(グローバルSIM)、特にLow Data Volumeプランを使う場合、Beamの活用を考えないともったいないですね。
色々難しいところはありますが、HTTPSをHTTPにするだけでもかなりの効果があります。まずはこのあたりから試してみましょう。

なお、これは小さいデータを多数送るような場面で特に効果を発揮します。データが大きな場合は全体に対するペイロードの比が最初から高いため、ここまで改善しない可能性が高いです。ただし、今まではオーバーヘッドがあるから仕方なくデータをまとめていたが、オーバーヘッドが小さくなることで細かく送ってリアルタイム性を上げる、という方向には使えると思います。

またMQTTSをを使用している場合は、初回はTLSハンドシェイクがかなり重いものの、以降は常時接続であること、MQTTのヘッダがかなり小さい事から、TCP → HTTPSエントリと同程度の通信量になります。（なお、今回はTCPを接続、送信、受信、切断で見ましたが、TCPを常時接続しておけば接続、切断部分の通信量はかかりません。）そのため、すでにMQTTSで構築できているならそれはそれでいいかもしれません。これはどちらかというとMQTTSより単なるTCPの方が扱いが簡単で、実装・保守がしやすいという方がメリットですかね。（ただし常時接続の場合です。MQTTSはクライアント証明書認証も行うため、TLSハンドシェイクがさらに大きくなり、接続・切断を繰り返すような場面には向かないと思います）

以上です！

# 消費電力の削減効果の計測がしたい。よね？

ここで終わるつもりだったんですよ。もう１万文字越えてますし、もうやることも無いかなって。
でも気付いてしまったんです。僕は[なんかとにかくすごい電力計](https://www.hioki.co.jp/jp/products/detail/?product_key=649)を開発・製造・販売している[計測器メーカー](https://www.hioki.co.jp/jp/)に在籍しているということに。こんなすごそうなものがあるなら、ラズパイやらWioLTEやらの電力測って、省電力効果を数値として出せますよね。

ということでまだやることありました。むしろこれやらないとダメだろ、と思いまして、お隣の部署に借りに行きました。

僕「趣味のブログ書くのに使いたいので、良い感じの電力計を貸してください！」

開発リーダーのTさん「どういうことですか？」

僕「今使ってるサービスの効果にこれ使えば省電力にできる、って謳っているものがあって、それを試してやろうかと。ウチの電力計ってそういう省電力の効果測定とかの用途でよく使われてるんですよね？」

Tさん「わかりやすいところでは家電の消費電力評価なんかにはよく使われてますね。というか自分のところの製品もこれで評価してるでしょ。で、それはどういうパターンの電力消費なんですか？電力計といっても色々あるので」

僕「うーん、電池での動作が想定されていて、普段はほとんど消費しない状態でスリープしてるんだけど、たまに立ち上がって携帯電波の送信のために100mAを越えるくらいの電力を一時的に消費して、終わったらまたスリープ状態に入るような感じです」

Tさん「なかなか難しいこと言いますね。。スリープ時の小さい電力の測定と動作時の大きな電力の測定を両立させられるのは、結構上のクラスの電力計が必要なんですよね」

僕「（そうなんだ。。）」

Tさん「じゃあこれしばらく使ってていいですよ。これは[PW3335](https://www.hioki.co.jp/jp/products/detail/?product_key=660)っていう電力計で、待機時の電力も測れることに注力してるモデルなので。多分これなら測れるはずです。」

僕「ありがとうございます！」

ということで借りてきました！しばらく使えます。

![IMG_20191214_153655.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/ca065ead-8c39-7bb1-43f4-48354a681b3c.jpeg)

とりあえず何もつながっていない状態のラズパイ。電力は2.353W。思ったより消費電力大きいな。。

測定の方法としては、５分間の積算電力（電力消費を一定時間加算した合計を出すもの。単位はWh。1Wの電力消費が1時間続いたら1Wh）を5分で割って消費電力(W)を算出します。本当は１時間で測定していたいですが、時間かかりますので。

# ラズパイの消費電力測定

先ほどのパターンの通信を5秒おきにさせた場合と、参考としてUSBモデム(AK-20)を挿していない状態、挿しただけでなにもしていない状態で計測しました。測定の様子を動画で見せられないのが残念ですが、通信してる時には電力がぐっと上がっているのが目に見えて分かります。

結果はこちら！

|方法|消費電力|USBモデム挿しただけとの比較|
|:--|--:|--:|
|直接CLI|4.11120W|+1.44276W|
|HTTPエントリ|3.35436W|+0.68592W|
|TCP → HTTPSエントリ|3.28356W|+0.61512W|
|UDP → HTTPSエントリ|2.93724W|+0.26880W|
|UDP + バイナリパーサー|2.93172W|+0.26328W|
|USBモデム挿しただけ|2.66844W|-|
|USBモデム挿していない|2.34984W|-0.3186W|

これは、、効果あり！ですよね？

直接CLI >> HTTPエントリ >≅ TCP → HTTPSエントリ > UDP → HTTPSエントリ ≅ UDP + バイナリパーサー > USBモデム挿しただけ > USBモデム挿していない

という感じですね。なるほどね〜。

HTTPエントリとTCP → HTTPSエントリがほぼ同じ、UDP → HTTPSエントリとUDP + バイナリパーサーがほぼ同じになることから考えて、通信量そのものよりもパケット数、つまり通信回数が主要なファクターと考えられます。バイナリパーサーはバイナリにすることでパケットを分割しなくて済む、という場合に効果を発揮する事になりますね。直接CLIはパケット数がすごく多いということと、おそらく暗号化や署名といった重い処理が高いCPU負荷になっていることも一因なのでしょう。

あとちょっと疑問を感じた動きがありまして、USBモデム挿しただけの場合は2.67W程度なのですが、1回でもパケット送信をするとその後送信して無くてもその後1分ちょっと程度の時間2.9W近くに上がったままになるんですよね。1分ちょっと過ぎればまた2.67W程度に戻る。これはUSBモデムが送信後しばらくは受信待ち状態みたいな感じになっているのでしょうか？あるいはpppdがそういう制御をしている？これが送信完了を確認したらスパッと切れるようになれば、もう少し改善できそうです。こうすれば良いんじゃ無い？という情報があればコメントにでも書いていただければ試してみたいと思います。

# Wio LTEの消費電力測定

「ラズパイはもとから電力消費高くてどうせ電源供給必須なんだからあんまり消費電力は気にしてない。それよりも電池駆動の組み込みボードでどうなるか知りたいよね。」というご意見もあると思います。

僕もそう思って、金曜の昼過ぎに[Grove IoT Starter kit for SORACOM](https://soracom.jp/products/kit/grovestarter_kit_lte/)をポチったのですが、
土曜の午前中にもう届きました。早すぎる。

ということで取りかかりましたがWio LTEというかArduinoの使い方が良く分からないので苦戦しています。というかこれでHTTPSできるのか？
~~こちらはまた結果が出たら追記します。電力計借りてる間に！~~

(2019/12/16追記) 測定しました！

Wio LTEの消費電力の測定にあたっていくつか困った事がありまして、まず電源にラズパイ用のACアダプターを使っていたのですが、これだけで50mW程度消費するんですよね。ラズパイの時はそこまで気にしていませんでしたが、Wio LTEはだいたい数百mW程度の電力になるので、この程度でもかなり大きな誤差になります。

ちゃんと電力を測定するためにはUSBの電源供給の部分で測定しないといけません。
以下の図のような形で、Iとその隣の±にUSBの電源線(赤い線)、Uの隣の±にUSBのグランド線(黒い線)をつなぐ必要があります。
![スクリーンショット 2019-12-16 17.36.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/d8ab2b4b-f21f-8c31-a934-23c31632e986.png)

そういう線はありそうなものですが、手近に無かったので、自分の持っているUSBケーブルを切って、切断して配線しました。
![IMG_20191217_114249.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/d62bf2ac-b8f0-614b-aa6a-8db3b117ade9.jpeg)
この赤と黒の線を電力計に正しく接続します。（今回はそのままつないでしまいましたが、線にY端子などをつけるとより安全です）
![IMG_20191217_120036.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/dc80e9aa-2c7a-be1b-f90f-29cb4b6bc5e6.jpeg)

しかしUSBの線細いですね。。こんなのに2Aも流して大丈夫か？とりあえずちゃんとUSBの5Vと、その電流の100mA〜300mA程度の電流が測定できるようになりました。

次にWio LTEのコードなのですが、AWS CLIなどは用意されていないので、直接CLIの部分は同等のアクセスをHTTPSですることとしました。HTTPSはライブラリのHttpPostがhttpsにも対応しているようなので、それを使うことができました。モデム自体にHTTPS通信をする機能が実装されているのかな？
https://seeedjp.github.io/Wiki/Wio_LTE_for_Arduino/Reference-ja.html#HttpPost

HTTPアクセスもこれでやったのですが、5秒おきにアクセスしているとたまに詰まってしまって30秒ほど待機状態になってしまうことがあったので、今回の実験はすべてアクセスは30秒ごと、計測時間は10分としました。ラズパイの時よりも回数は減ってしまいますが。。

また、TCP → HTTPエントリポイントに対して、TCP接続、送信、受信、TCP切断、とすると、なぜかTCP切断のところで切断が失敗する、という謎の現象が起こりました。こちらは解決できていません。10秒でタイムアウトして、その後もう１回切断すると切断でき、その後は同様に動きます。（同じように次の接続でも切断が失敗します。もう１回の切断をしないと今度は接続が失敗します）そういうこともあって、TCP → HTTPエントリポイントの結果はやや不安です。

最後の問題は、モデムの状況によって？電波状況の違いによって？消費電力が変動しているように思えることです。たとえばこちらをご覧ください。
![送信電力が下がる謎.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/343d66cf-bfb3-9453-068c-054a24677110.png)

HTTPでの消費電力を測定していたのですが、途中でピークがあからさまに変わっていることが分かりますね。動作中ですので配置もプログラムも変わっていません。これのせいで何回測定し直したか。。モデムの問題だとしたら自分でATコマンドで制御できるようになれば解消できるようになるかもしれません。仮に電波状況によって消費電力が変わるのであれば、、設計上かなりきついことになりますね。。この「現場状況がダイナミックに変わる」というのがIoTの難しいところな気がする。皆さんそのあたりはどう考えているんだろうか。

などと色々ありましたが、一通り確からしい結果は得ました。

各測定状況での電力をプロットするとこのようになります。(PW3335は対応アプリケーションで測定結果のCSVを取得できるので、CSVをもとにグラフにしています)

![スクリーンショット 2019-12-17 7.49.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/2248bec0-e72e-3ad8-b7ba-7d12280bb574.png)
![スクリーンショット 2019-12-17 7.58.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/208d85db-e26b-fbde-cb51-8a303b345022.png)
![スクリーンショット 2019-12-17 8.01.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/daa44aad-ed48-bed5-f2f6-41a5af6aaefb.png)
![スクリーンショット 2019-12-17 8.15.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/aa9617a4-0dbe-9e55-9a86-df85e59db20b.png)
![スクリーンショット 2019-12-17 8.32.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/0d68fecf-9dd6-ce69-b833-05a4d3057f33.png)
![スクリーンショット 2019-12-17 11.31.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/d54ebc13-5714-fbf6-178e-13c79771e2ac.png)
![スクリーンショット 2019-12-17 9.04.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/ffd6d44b-f54c-c3e0-1d00-e26747175557.png)

消費電力をまとめると以下の表になります。

|方法|消費電力|接続だけとの比較|
|:--|--:|--:|
|HTTPS|448.2mW|+66.4mW|
|HTTPエントリ|442.0mW|+60.2mW|
|TCP → HTTPSエントリ|(457.9mW)|(+76.1mW)|
|UDP → HTTPSエントリ|435.7mW|+53.9mW|
|UDP + バイナリパーサー|434.5mW|+52.7mW|
|接続だけ|381.8mW|-|
|起動だけ|300.1mW|-81.7mW|

HTTPS > HTTPエントリ > UDP → HTTPSエントリ ≅ UDP + バイナリパーサー > 接続のみ > 起動のみ
という傾向自体は変わらないですね。やはり効果ありです。積極的にSORACOM Beam使っていきましょう！
（前述の通りTCPは切断がなぜか失敗する問題により実力以上に高く出てしまっているため、カッコをつけています。ちゃんと出来ればHTTPより少し小さいくらいになるはず）

# 組み込み機器における消費電力管理

やや本題とは外れるのですが、接続だけしている状態とUDPのバイナリ送信との間には大きめの差があります。これが何故起こるかを解明したい。電源投入から10分間の電力の推移はこのようになります。
![スクリーンショット 2019-12-16 18.28.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/542185/ac7eeb4a-6ca3-4a9a-05c1-509577ac7bd0.png)
最初電源が入って、初期設定をして、ソラコムに接続して、という部分が一段落するまでにおおよそ20秒ほどかかっているのですが、それからは時折ピークはでるものの、0.43W程度のベースと0.50W程度のピークが1.28秒ごと程度で繰り返される、というパターンです。

ところが280秒程度のところから様子が変わります。ピークが0.45Wくらいまでしか上がらなくなります。（表の「接続だけ」はこの状態での消費電力です）

1.28秒ごとにピークが出るのは、DRX(Discontinuous Reception)という携帯基地局からの着信を確認する為の待ち受け状態です。([ソラコムの公式ガイドブック](https://www.amazon.co.jp/%E5%85%AC%E5%BC%8F%E3%82%AC%E3%82%A4%E3%83%89%E3%83%96%E3%83%83%E3%82%AF-SORACOM%E3%83%97%E3%83%A9%E3%83%83%E3%83%88%E3%83%95%E3%82%A9%E3%83%BC%E3%83%A0-%E3%82%BD%E3%83%A9%E3%82%B3%E3%83%A0/dp/4296102001)に書いています)ただ、これが通信を一定時間していないと下がる理由は不明です。モデムが何らかの省電力モードに入っているのかも知れません。

この状態でも通信はつながっているようで、再度Wio.ActivateしなくてもSocketOpenはできました。ただし、1回でもSocketOpenすると、またしばらくはピークが高い状態になります。ラズパイでも似たような現象がありましたが、これが接続をしているだけの状態と、送信した状態との大きな差の原因と考えられます。

このように、機器の色々な状態、および操作に対して、どのくらい電力を消費しているのかをまとめておくと有用そうです。例えば、以下のようなものが把握したくなってきます。

- LTEモデムの電源を切った状態と入れた状態との差
- 1回の接続にかかる電力量
- 1回あたりのUDP送信で消費する電力量
- ○分以内の送信間隔なら常時接続が有利、○分以上の以上の送信間隔なら都度接続が有利

また、今回はセンサを使いませんでしたが、

- 温度を１点取るのに必要な電力量
- ブザーを1回ならすのに必要な電力量
- GPSを1回使用するのに必要な電力量

などが分かれば、1日どの機能が何回使えるのか、が算出できそうです。ロールプレイングゲームのMP管理にちょっと似てますね。実際バッテリ残量は残りMP(無くなると死ぬからHP?)のようなもので、何かをすると消費し、無くなると使えなくなります。ちょっと面白そうなので、次回の記事ではWio LTEのボードで各操作どの程度の電力を消費しているのか、実測してみたいと思います。お楽しみに！

# まとめ

SORACOM Beamを使うことで、クラウドにデータをアップロードするといった良くあるユースケースでも98%もの通信量が削減できることが測定できました。これにより通信料金も98%削減できることがわかりました。（今回のような場合はですが）

また通信回数を減らすことにより、消費電力の削減にも確実に効果があることが測定できました。これは素晴らしいですね。
SORACOMをうまく使っていいプロダクトを作りましょう！

最後に、突然の謎の依頼にも関わらず電力計を貸してくれたTさんに感謝を捧げます。
それでは！