IoTにおけるソフトと特徴
- Arduino
- イベント駆動
 
 - MQTT
- 軽量プロトコル
 - publish/subscribe型のMQ
 
 
Arduinoとは
- 無償で使えるマイコン用プログラム作成アプリ
- マイコン毎にアドオンがある(ex, ESP8266)
 
 - スケッチ(=プログラム)はsetup/loopで構成
- setup: 電源入り後一度だけ呼ばれる
 - loop: (電源切るまで)繰り返し呼ばれる
 
 - 提供されているスケッチ例を改造して動かす
 
$brew cask install arduino
MQTTとは
- Message Queuing Telemetry Transport
 - 非常に軽量なプロトコル
- 2000年代初めに登場し標準化
 - TCP/IP上で動く
 
 - publish/subscribe型のメッセージ転送
 - IoT/モバイルに適する
- センサーデバイス
 - Facebook Messengerで使われている
 
 
HTTPよりも
- 軽量(ヘッダが最小2バイト)1・優れた処理速度・省電力
- HTTPではヘッダのオーバーヘッドが高い
 - AgostoのテストによるとHTTPSの10倍以上オーバーヘッドが低い
 
 - IoTの利用場面に適している
- 貧弱な電波環境(通信帯域制限)
 - バイト毎に料金・バッテリーを消費する環境
 
 
HTTPヘッダとの比較
$curl --head https://www.yahoo.co.jp/
HTTP/1.1 200 OK
Date: Tue, 18 Jul 2017 18:10:57 GMT
(中略)
$curl --head https://www.yahoo.co.jp/ | wc -c
703
- 最小まで減らすとしたら
HTTP/1.1 200 OKの15byte - MQTTでは最小2バイト1
 - 通信量が膨大になるほどこの10byteの差が意味を持つ
 
暗号化
- TLSを使った暗号接続が可能
- port: 8883
 
 - ただし通信毎に認証が必要なので軽量さは失われる2
- メッセージ全体のサイズが大きいならヘッダの10バイト差は誤差
 - MQTTとHTTPsどちらが適しているか要検討
 
 
HTTPとのすみ分け
| protocol | 適した用途 | 
|---|---|
| http | 1対1で画像など大きなデータをやりとりしたい, secureな通信がしたい | 
| mqtt | 複数台から小さいデータを大量にもらいたい | 
Publish/Subscribe
- メッセージの送信者(publisher)が特定の受信者(subscriber)に直接メッセージを送信しない
 - メッセージのやりとりにはBrokerと呼ばれる中継serverが必要
- サーバーがメッセージを保管するため受信側の状態に関係なくメッセージを送れる
- オフラインでもOK
 
 - publisher/subscriberがMQTT client
 
 - サーバーがメッセージを保管するため受信側の状態に関係なくメッセージを送れる
 - 接続時のデバイスIDが被ると古い接続が切れる
 
出典: Securing MQTT - BuildingIoT 2016 slides
message(= topic + data)
- subscriberはbrokerへtopicの受信を申し込む
 
- 接続後一度だけで良い
 
- brokerはtopicへのpublishがあると接続中のtopicを申し込んだsubscriberへmessageを送信
 
- 過去分は送れない(最後のmessageはオプションで受け取れる)
 - publisherにsubscriberのアクセス情報は通知されない
 
出典: Paho Python client for MQTT and G-code Visualization Talks, Chennaipy
topic
- 一般的に/(スラッシュ)で階層化3
- ex, tokyoA/temp
 
 - ワイルドカード(#,+)
 - mosquittoなどの一部ブローカーにはACL機能有り
 
QoS
- client間のメッセージ到達保証レベル(Quality of Service)
 - 通常は0、コントロール系のメッセージは1以上、が基本
- 1以上はbrokerでstoreが必要
 
 - Kafkaの例だが佐伯さんのスライドがわかりやすい
 
| level | desc | example | 
|---|---|---|
| 0 | At most once(メッセージ到達保証無) | subscriberの受信失敗時のケアがない、など | 
| 1 | At least once(届くけど重複するかも) | subscriberのACK受信失敗時に再送、など | 
| 2 | Exactly once(確実に重複無く届ける) | transaction制御、速度低下 | 
(閑話)ログの質が精度を分ける
- 米テックジャイアントのログ収集は実は雑
- 重複やロストは気にしない
 - ログ設計はすごい。デモグラなど混ぜて1レコードに豊富な情報量
 
 - 重複もロストも許さないログでディープラーニングにかけたら、モデルの精度がテックジャイアントより高かった
- precision/recallがほぼ1
 - 1レコードは購買やPVなど基本情報のみ
 - 日本向けサービス同士の比較なので、日本語の壁など外的要因な可能性も
 
 
※社外秘のため詳細は公開しません
MQTTブローカー
- OSS
 - cloud
 - 公開MQTTテスト用ブローカー
 
MQTTクライアント
- OSS
- 
paho
- 様々な言語に対応
 
 - 
PubSubClient
- Arduinoクライアント
 - 日本語のスケッチ例はこちら
 
 
 - 
paho
 
mosquitto & paho by Python
MQTT通信の実例
Macで下記セットアップ
$brew install mosquitto
# mosquitto起動のため以下のどちらかを実行
# bg
$brew services start mosquitto
# fg
$/usr/local/opt/mosquitto/sbin/mosquitto -c /usr/local/etc/mosquitto/mosquitto.conf
$pip install paho-mqtt
paho pub.py
Pythonクライアントのチュートリアルを真似つつ
pub.py
import paho.mqtt.client as mqtt
import time
client = mqtt.Client()
client.connect('localhost', 1883, keepalive=60)
client.loop_start()
while True:
  client.publish('world/darai0512', 'test')
  time.sleep(1)
paho sub.py
sub.py
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, respons_code):
  print('connected')
  client.subscribe('world/#')
def on_message(client, userdata, msg):
  print(msg.topic + ' ' + str(msg.payload))
client = mqtt.Client()
client.on_connect = on_connect
client.on_message = on_message
client.connect('localhost', 1883, keepalive=60)
client.loop_forever()
Let's try MQTT
$python pub.py &
$python sub.py
world/darai0512 test
world/darai0512 test
...

