paho-mqttでIoTの第一歩

IoT等の構築でraspberry piをいじっているときなど、遠隔からwifiごしに何かしらの機械のリモートコントロールしたい、 または遠隔から現在の機器の状況を知りたいということがある。ここではそういったことを得意とするMQTTをC++を使って説明する。




Paho-mqttの導入


paho-mqttはpythonでmqtt通信をするためのパッケージで、pipがあれば、以下のコマンドで簡単にインストールできる。

$ pip install paho-mqtt

Publish


参考: Python で MQTT
まずはサンプルコードをのせる。

#!/usr/local/bin/python3 # いつもの
# -*- coding: utf-8 -*- # いつもの
      
from paho.mqtt import client as mqttcli Paho-mqttをインポート
      
# ブローカーに接続できたときの処理
def on_connect(client, userdata, flag, rc):
  print(f"Connected with result code {rc}")
      
# ブローカーが切断したときの処理
def on_disconnect(client, userdata, rc):
  if rc != 0:
  print("Unexpected disconnection.")
      
# publishが完了したときの処理
def on_publish(client, userdata, mid):
  print(f"publish: {mid}")
      
# メイン関数
def main():
  client = mqttcli.Client() # インスタンスの作成
  client.on_connect = on_connect # 接続時に呼ばれる関数を自分の書いた関数に紐付け
  client.on_disconnect = on_disconnect # 切断時に呼ばれる関数を自分の書いた関数に紐付け
  client.on_publish = on_publish # メッセージ送信時に呼ばれる関数を自分の書いた関数に紐付け
  client.connect("<MQTTブローカーのアドレス>", <MQTTブローカーのポート(default: 1883)>, <接続待ち時間>) # 接続先は自分自身
  client.publish("test/topic", "testmessage", qos=0, retain=True) # トピック名とメッセージを決めて送信
  # 通信処理スタート
  client.loop_start() # subはloop_forever(),pubはloop_start()で起動

      
if __name__ == '__main__': # プログラム実行時にmain()を実行
  main()

ここで、これを実際に実行するとMQTTブローカーにtest/topicというトピックで「testmessage」という文が送られる。ここらへんは適宜変える。
MQTTブローカーもプログラム実行も同じコンピューターで行う場合はMQTTブローカーのアドレスはlocalhostで良い。

送られたかどうかの確認はこのプログラムを実行する前に端末(ターミナル)を2つ用意して、 片方の端末でここのSub側のコマンドを実行しておくと、 このプログラムを実行したときにメッセージが表示される。

main関数内ではプログラムの前の方で書いてある関数を紐付けている。 もし接続時/切断時/メッセージ送信時に付け加えたい処理がある場合は前の方の関数内にそれぞれ書く。 publish()の中の他の引数はオプションで次の意味を持つ。

Subscribe


参考: Python で MQTT
まずはサンプルコードをのせる。

#!/usr/local/bin/python3 # いつもの
# -*- coding: utf-8 -*- # いつもの
      
from paho.mqtt import client as mqttcli Paho-mqttをインポート
      
# ブローカーに接続できたときの処理
  def on_connect(client, userdata, flag, rc):
    print(f"Connected with result code {rc}") # 接続できた旨表示
  
      
# ブローカーが切断したときの処理
def on_disconnect(client, userdata, rc):
  if rc != 0:
  print("Unexpected disconnection.")
      
# メッセージが届いたときの処理
def on_message(client, userdata, msg):
  # msg.topicにトピック名が,msg.payloadに届いたメッセージ本文
  print(f"Received message: {bin(int(msg.payload))}, topic: {msg.topic}, QoS: {msg.qos}")
      
def main():
  client = mqttcli.Client() # インスタンスの作成
  client.on_connect = on_connect # 接続時に呼ばれる関数を自分の書いた関数に紐付け
  client.on_disconnect = on_disconnect # 切断時に呼ばれる関数を自分の書いた関数に紐付け
  client.on_message = on_message # メッセージ到着時に呼ばれる関数を自分の書いた関数に紐付け
  client.connect("localhost", 1883, 60) # 接続先が自分自身の場合
  client.subscribe(topic="test/topic", qos=0)
  client.loop_forever() # 永久ループで待ち続ける
      
      
if __name__ == '__main__': # プログラム実行時にmain()を実行
  main()

サンプルプログラムではconnect()の中身をlocalhost, 1883, 60としているが、 これはPublishのconnectと同じ引数なので、各自変更する。

subscribeでもQoSを指定できるが、必ずPublish側のQoSと同じか小さくする。ここでのQoSはSubscribe側とMQTTブローカーの通信の品質。
メッセージを受け取った後の処理、例えばonというメッセージを受け取ったらLEDをつけるなどはon_connect()の中に書く。