mosquitto，paho-mqttで画像のやりとり

MQTT通信で画像のやりとりをした際の備忘録．ここでは，MQTT通信については詳細に説明しないが，MQTTはメッセージを送信する"Publisher"，メッセージを受信する"Subscriber"，メッセージを仲介してやり取りする"Broker"の3端末が存在する．
なお，MQTT通信にはmosquittoとpaho-mqttで行った．

## 使用した技術
### mosquitto
MQTTプロトコルを利用するためのオープンソースのブローカーである．mosquittoのインストールによってMQTT通信が手軽に実現できる( https://mosquitto.org/ )．

### paho-mqtt
MQTT通信をアプリケーション上に実装するために必要なオープンソースのライブラリ．利用するにはmosquittoが必要．

## 手順

### 環境
Publisherに Raspberry Pi3 Model B(OS:Raspbian)を，BrokerとSubscriberにVMのUbuntu 16.04を使用した．

### mosquittoのインストール
[Download|Eclipse Mosquitto](https://mosquitto.org/download/) にあるように，Ubuntu系へのインストールはターミナルで簡単にできる．
Brokerへのインストールは

```terminal
$  sudo apt install mosquitto
```
でできる．また，Publisher/Subscriberへのインストールは

```terminal
$  sudo apt install mosquitto-clients
```
でできる．

なお，最新版のmosquittoが欲しい場合は上記手順の実行前に

```terminal
$  sudo apt-add-repository ppa:mosquitto-dev/mosquitto-ppa
$  sudo apt update
```
を行い，mosquitto-dev PPAをリポジトリリストに追加する．

### paho-mqttのインストール
pipを用いてインストールする．

```terminal
$  pip install paho-mqtt
```


### 画像のやりとり

手順としては以下のとおりである．

1. Brokerの準備
1. SubscriberがBrokerにTOPICをSubscribeする．
2. PublisherがBrokerに対して，TOPICとしてファイル等をPublishする．

#### Broker

あらかじめ，mosquittoが起動しているかどうかを確認しておく．
確認コマンドは以下の通り．

```terminal
$  systemctl status mosquitto
```

このとき，`ACTIVE: active (running)`と表示されればOK．
もし，表示がされていない場合は`$  systemctl start mosquitto`を実行し，mosquittoを起動しておく．

#### SubScriber

以下のプログラム`Subscribe.py`をSubscriberに保存し，変数`host`と`topic`の値を書き換える．
※python2系とpython3系でプログラムが少し異なります．

<details><summary>【python2系 Subscribe.py】</summary><div>

```python:Subscribe.py
# coding: UTF-8
# MQTT Pahoのインポート
import paho.mqtt.client as mqtt

##################
# hostとtopicは書き換える
##################
# MQTT Brokerの情報
host = 'XXX.XXX.XXX.XXX' # BrokerのIPアドレスを指定
port = 1883 # MQTTのポート 通常はこのままでOK
topic = 'TOPIC_NAME' # Subscribeするtopic名を記述

# MQTT Brokerへの接続する関数
def on_connect(client, userdata, flags, respons_code):
    print('status {0}'.format(respons_code))
    client.subscribe(topic)

# 受信したバイナリデータを output.jpg として保存する関数
def on_message(client, userdata, msg):
    outfile = open('./output.jpg', 'w') # python 2系の場合
                                        # python 3系の場合は第2引数を 'wb' にする
    outfile.write(msg.payload)
    outfile.close

if __name__=='__main__':
    client = mqtt.Client(protocol=mqtt.MQTTv311)
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect(host, port=port, keepalive=60)
    client.loop_forever()
```
</div></details>

<details><summary>【python3系 Subscribe.py】</summary><div>

```python:Subscribe.py
# coding: UTF-8
# MQTT Pahoのインポート
import paho.mqtt.client as mqtt

##################
# hostとtopicは書き換える
##################
# MQTT Brokerの情報
host = 'XXX.XXX.XXX.XXX' # BrokerのIPアドレスを指定
port = 1883 # MQTTのポート 通常はこのままでOK
topic = 'TOPIC_NAME' # Subscribeするtopic名を記述

# MQTT Brokerへの接続する関数
def on_connect(client, userdata, flags, respons_code):
    print('status {0}'.format(respons_code))
    client.subscribe(topic)

# 受信したバイナリデータを output.jpg として保存する関数
def on_message(client, userdata, msg):
    outfile = open('./output.jpg', 'wb') # python 3系の場合は第2引数を 'wb' にする
    outfile.write(msg.payload)
    outfile.close

if __name__=='__main__':
    client = mqtt.Client(protocol=mqtt.MQTTv311)
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect(host, port=port, keepalive=60)
    client.loop_forever()
```
</div></details>

このプログラムは，指定したbrokerのTOPICに対してsubscribeを行い，受信したデータをoutput.jpgとして保存するものである．

保存後は，以下のコマンドを実行する．

```terminal
$  python Subscribe.py
```

#### Publisher

最後に，Publisherが送信したい画像をPublishする．

```terminal:Publisher
$  mosquitto_pub -d -h XXX.XXX.XXX.XXX -t 'TOPIC_NAME' -f Pub.jpg
```

使用しているオプションを以下に示す．

- -d：デバッグモード
- -h：BrokerのIPアドレスを指定する．何も指定しない場合はlocalhostとなる．
- -t：topic名を指定する．(必須)
- -f：送信するファイル名

以上で，MQTTでファイルの送受信が可能となる．