IoT時代のプログラミング(主にMQTTについて)


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)

  1. subscriberはbrokerへtopicの受信を申し込む
    • 接続後一度だけで良い
  2. 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ブローカー


MQTTクライアント


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
...