RabbitMQのMQTT Adapterを使ってみる

業務でRabbitMQのMQTT Adapterを使う必要が出てきたので、勉強がてらにこれらの動作確認を行った際の備忘録です。   

*※RabbitMQ？MQTT?なにそれ？という状態からのスタートでしたので、かなり初歩的なことしか確認してないです。m(_ _)m*

**<やりたかったこと>**
Ubuntu上のRabbitMQの任意のqueueに、MacPC上でpublish(MQTT)したメッセージを格納する

**<動作環境>**

- Mac
OS: 10.13.6
python: 3.5.2 (MQTT publishの実装で使用)

- Ubuntu
OS: 16.04
RabbitMQ: 3.7.7
※UbuntuはMac上のVirtualBox上で動作してます（VirtualBoxはブリッジアダプターとして動作）


## 1.Ubuntu上にRabbitMQをインストール

Ubuntu上にRabbitMQをインストール方法自体は、検索すれば色々ヒットするので割愛
私の場合は以下のサイトを参考にインストールしました。
[参考サイト](https://www.vultr.com/docs/how-to-install-rabbitmq-on-ubuntu-16-04-47)

※上から順番にコマンドをポチポチすればOK

## 2.RabbitMQのMQTT Adapterの有効化

[参考サイト(本家)](https://www.rabbitmq.com/mqtt.html)

以下のコマンドを入力する

```bash

sudo rabbitmq-plugins enable rabbitmq_mqtt
```

プラグイン適用に成功すると、こんなメッセージが出てくるはず

```bash
The following plugins have been enabled:
  rabbitmq_mqtt

started 1 plugins.
```

## 3.MQTT動作確認用にテストアカウントを作成

以下のコマンドでアカウントを作成

```bash
# username and password are both "mqtt-test"
rabbitmqctl add_user mqtt-test mqtt-test  #第一引数がuser, 第二引数がpassword
rabbitmqctl set_permissions -p / mqtt-test ".*" ".*" ".*"
rabbitmqctl set_user_tags mqtt-test management
```

※当初、初期アカウント（user:guest/password:guest）で、Mac側から動作確認をしようとしたが、MQTTのconnectionをはろうとしていたがエラーで弾かれていた。そのため、別のアカウントを用意しました。ちなみに以下のエラーが出力されてました

```bush
2018-09-08 15:29:14.475 [info] <0.562.0> MQTT vhost picked using plugin configuration or default
2018-09-08 15:29:14.476 [warning] <0.562.0> MQTT login failed for "guest" access_refused (access must be from localhost)
2018-09-08 15:29:14.477 [info] <0.562.0> MQTT protocol error connect_expected for connection 192.168.43.39:53179 -> 192.168.43.126:1883
```
[公式サイト](https://www.rabbitmq.com/mqtt.html)に以下の記載があるのを見落としてましたね。。。
>When an MQTT client provides no login credentials, the plugin uses the guest account by default which will not allow non-localhost connections. 

## 4.MQTT Adapterの設定をconfigに記載

[公式サイト](https://www.rabbitmq.com/mqtt.html)の設定をほとんどパクりました。
変更した点は以下
「default_user」と「default_pass」を#3で作成したアカウントに変更
「exchange」をamq.fanoutに変更（デフォルトで用意されているfanoutのexchange）

/etc/rabbitmq/rabbitmq.config

```bash
 {rabbitmq_mqtt, [{default_user,     <<"mqtt-test">>},
                  {default_pass,     <<"mqtt-test">>},
                  {allow_anonymous,  true},
                  {vhost,            <<"/">>},
                  {exchange,         <<"amq.fanout">>},
                  {subscription_ttl, 1800000},
                  {prefetch,         10},
                  {ssl_listeners,    []},
                  {tcp_listeners,    [1883]},
                  {tcp_listen_options, [{backlog,   128},
                                        {nodelay,   true}]}]}
```

※上記ファイルについてですが、私の環境ではインストールした段階では作成されていなかったので、以下のファイルを解凍して上記のパスに配置しました。
/usr/share/doc/rabbitmq-server/rabbitmq.config.example.gz

設定が完了したらRabbitMQを再起動する

```bash
sudo systemctl restart rabbitmq-server.service
```

## 5.MQTT publish受信用のqueueを作成

RabbitMQの管理用画面をwebブラウザで開く
デフォルトでは、``http://localhost:15672/``で開く

①Adminアカウントでログイン（デフォルトはguest/guest）
![rabbitMQ_manage1.png](https://qiita-image-store.s3.amazonaws.com/0/288169/7539aa26-5624-f9f1-56c8-61c299bb68ca.png)

②Queueタブを選択
③任意のQueue名を入力
④Add queueをクリック（※他のパラメータはデフォルトのまま）
![rabbitMQ2.png](https://qiita-image-store.s3.amazonaws.com/0/288169/3b80d072-92cc-5803-d7b9-73cec55f62ad.png)

⑤Queueが追加されていることを確認
![rabbitMQ3.png](https://qiita-image-store.s3.amazonaws.com/0/288169/4206e401-716b-d59d-fa3a-3e0faef9e3a1.png)

⑥先ほど追加したQueueを選択し、「amq.fanout」をバインドする
※amq.fanoutはfanoutのexchangeのため、他のパラメータの設定は不要
![rabbitMQ4.png](https://qiita-image-store.s3.amazonaws.com/0/288169/3b5700f1-baa5-073d-14c9-b31af8288dda.png)

これで、exchangeとqueueのバインドが完了しました

RabbitMQ側の準備は一旦これで完了です

## 6.MQTT publishを行うpythonスクリプトの作成

こちらはMac側で行いました
paho-mqttを使用して、MQTTのpublisherを作成しますので、
pip インストールでpaho-mqttを落としておきました

以下のコマンドを入力

```bash
pip install paho-mqtt
```

作成したpythonスクリプトは以下になります

mqtt_publish.py

```python
import paho.mqtt.client as mqtt

host = 'xxx.xxx.xxx.xxx' #UbuntuのIPアドレスを設定してください
port = 1883
topic = 'amq.fanout'

jsonString = '''
{
    "device_A": {
        "data1": 45,
        "data2": 60,
        "data3": 90
    }
}
'''

client = mqtt.Client(protocol=mqtt.MQTTv311)

client.connect(host, port=port, keepalive=60)

# メッセージ（jsonString）をpublishします
client.publish(topic, jsonString)

client.disconnect()

```

## 6.Publishを実行

以下のコマンドを入力して実行

```bash
python mqtt_publish.py
```

**<結果>**
作成したキューにメッセージが格納されてるっぽい。
![rabbitMQ5.png](https://qiita-image-store.s3.amazonaws.com/0/288169/00e5a981-0f87-e42a-05d0-b6e3b8b457f1.png)

メッセージの中身も確認できました！
![mqtt6.png](https://qiita-image-store.s3.amazonaws.com/0/288169/77ce7a68-4131-f0f9-cb66-bb1198a90f05.png)


以上

## 今後の課題
1.MQTTにて、fanout以外のexchangeでメッセージをQueueに格納するにはどうすれば良いのか？
※今後時間があれば調査したいと思います。情報お持ちの方いらっしゃったらご教示いただけると嬉しいです。。