MQTTとPahoで画像を送信する

## はじめに
前回，MQTT+TLS通信を行う[記事](https://qiita.com/udai1532/items/c0f58e73f76900a8469f)をあげましたが，その仕組みを利用してMQTTで画像を送信してみたいと思います．

前回の記事では，クライアントアプリケーションにMosquittoに付属して付いてくるmosquitto_pubとmosquitto_subを利用しました．これらを使って画像のやりとりも可能ですが，今回はPythonのmqtt-pahoライブラリを用いて画像の通信を行いたいと思います．

## Pahoを使ったメッセージ通信の例
以下にPublisherおよびSubscriberのPythonのソースコードを示します．

```Python:pub.py 
import paho.mqtt.client as paho

def on_connect(mqttc, obj, rc):
    mqttc.subscribe("$SYS/#", 0)
    print("rc: "+str(rc))

def on_message(mqttc, obj, msg):
    print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload))

def on_publish(mqttc, obj, mid):
    print("mid: "+str(mid))

def on_log(mqttc, obj, level, string):
    print(string)


if __name__ == '__main__':
    mqttc = paho.Client()
    mqttc.on_message = on_message
    mqttc.on_connect = on_connect
    mqttc.on_publish = on_publish


    mqttc.connect("localhost", 1883, 60)
    mqttc.publish("topic/test", "hello", 0)

    mqttc.loop_forever()

```

```Python:sub.py

import paho.mqtt.client as paho

def on_connect(mqttc, obj, rc):
    mqttc.subscribe("$SYS/#", 0)
    print("rc: "+str(rc))

def on_message(mqttc, obj, msg):
    print(msg.topic + " " + str(msg.qos) + " " + str(msg.payload))
    
def on_publish(mqttc, obj, mid):
    print("mid: "+str(mid))

def on_subscribe(mqttc, obj, mid, granted_qos):
    print("Subscribed: "+str(mid)+" "+str(granted_qos))

def on_log(mqttc, obj, level, string):
    print(string)


if __name__ == '__main__':
    mqttc = paho.Client()
    mqttc.on_message = on_message
    mqttc.on_connect = on_connect
    mqttc.on_subscribe = on_subscribe


    mqttc.connect(localhost, 1883,60)
    mqttc.subscribe("topic/test", 0)

    mqttc.loop_forever()

```

これら2つをブローカを通して通信することで，Pahoを用いたMQTTの通信が可能になります．

# 画像をMQTTで送る
今回の本題である画像をMQTTで送るために，先ほどのソースコードに手を加えます．

まず，Publisher側を修正していきます．今回はPublisherのソースコードと同じディレクトリにあるimage.jpgという画像ファイルを送信することを考えます．

今回は純粋にファイルオープンを行なって画像ファイルをバイナリに変換します．以下のようなソースコードになります．

```Python
    with open("image.jpg", "rb") as testfile:
        image = testfile.read()
    bitArray = bytearray(image)
```

この作成した`bitArray`を送信メッセージのボディ部分にします．最終的には以下のようなソースコードになります．

```Python:imgpub.py

import paho.mqtt.client as paho

def on_connect(mqttc, obj, rc):
    mqttc.subscribe("$SYS/#", 0)
    print("rc: "+str(rc))

def on_message(mqttc, obj, msg):
    print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload))

def on_publish(mqttc, obj, mid):
    print("mid: "+str(mid))

def on_log(mqttc, obj, level, string):
    print(string)

if __name__ == '__main__':
    mqttc = paho.Client()
    mqttc.on_message = on_message
    mqttc.on_connect = on_connect
    mqttc.on_publish = on_publish
  
    with open("image.jpg", "rb") as testfile:
        image = testfile.read()
    bitArray = bytearray(image)


    mqttc.connect(localhost,1883,60)
    mqttc.publish("topic/test", bitArray, 0)

    mqttc.loop_forever()

```

Subscriber側はメッセージ受信時に，逆の処理をしてあげれば良いだけです．以下にソースコード全体を示します．

```Python:imgsub.py

import paho.mqtt.client as paho


def on_connect(mqttc, obj, rc):
    mqttc.subscribe("$SYS/#", 0)
    print("rc: "+str(rc))

def on_message(mqttc, obj, msg):
    print(msg.topic+" "+str(msg.qos))
    with open("output.jpg", "wb") as outfile:
        outfile.write(msg.payload)
    outfile.close()

def on_publish(mqttc, obj, mid):
    print("mid: "+str(mid))

def on_subscribe(mqttc, obj, mid, granted_qos):
    print("Subscribed: "+str(mid)+" "+str(granted_qos))

def on_log(mqttc, obj, level, string):
    print(string)


if __name__ == '__main__':

    mqttc = paho.Client()
    mqttc.on_message = on_message
    mqttc.on_connect = on_connect
    mqttc.on_subscribe = on_subscribe


    mqttc.connect("127.0.0.1", 1883, 60)
 
    mqttc.subscribe("topic/test", 0)
    mqttc.loop_forever()

```

これらを実行することで画像をやり取りすることが可能になります．

## TLSを有効にする場合
冒頭に述べたMosquittoでSSL/TLSを利用する場合は，ディレクトリに`ca.crt`をコピーした上で，以下の記述を追加しましょう．(`ca.crt`の作り方については冒頭の記事を参照してください．)

```Python
# ~(省略)
mqttc.tls_set("./ca.crt")

#mqttc.connect("127.0.0.1", 1883, 60)
mqttc.connect("127.0.0.1", 8883, 60)

# （省略）~
```

Publisher，Subscriber側両方にこの記述を追加するだけでSSL/TLS通信が利用可能になります．


## まとめ
これでPahoライブラリを用いて，画像をMQTTで送受信することが可能になりました．
同じことをやろうとする方の参考になれば幸いです．