MQTT Subscriber ボックスを作る


## はじめに

今回は MQTT の Subscriber 側のボックスを作り、Pepper 君で動作させてみました。

Publisher 側で動作させてみた内容はこちら。

* [MQTT Publisher ボックスを作る](http://qiita.com/Suna/items/26dc236606f27dfafa16)
* [MQTT Publisher ボックスを作る その2](http://qiita.com/Suna/items/f0d0b1d24d24e5a172a2)

まだまだ、MQTT 勉強中です。


## MQTT Subscriber ボックス

MQTT の Python 用ライブラリとして、以下のライブラリを使用します。

* [Paho - Open Source messaging for M2M](https://eclipse.org/paho/)


### 設定項目

MQTT のブローカの情報と、取得するトピックの情報を設定します。

![2015040401.png](https://qiita-image-store.s3.amazonaws.com/0/20418/2d9a1ef3-ca3f-111a-41fa-f23e7c388818.png "2015040401.png")


### Python コード

MQTT ブローカに接続し、トピックを Subscribe します。その後、loop_forever で受信待機状態に。
プログラム終了時にはトピックを　Unsubscribe します。

ボックス内でのライブラリの使用方法は、以下の記事を参考にさせて頂きました。

* [Pepper用Tweetボックスをつくる](http://qiita.com/yacchin1205/items/3422b5066dcbfca63def)

(なんか見直してたら、コードを直したくなってきた)

```python
class MyClass(GeneratedClass):
    def __init__(self):
        GeneratedClass.__init__(self)

    def onLoad(self):
        self.framemanager = ALProxy("ALFrameManager")
        self.folderName = None

    def onUnload(self):
        import sys

        self.mqttc.unsubscribe(self.topic)

        if self.folderName and self.folderName in sys.path:
            sys.path.remove(self.folderName)
        self.folderName = None

    def onInput_onStart(self, payload):
        import sys, os

        self.folderName = os.path.join(
            self.framemanager.getBehaviorPath(self.behaviorId), "../lib")
        if self.folderName not in sys.path:
            sys.path.append(self.folderName)

        import paho.mqtt.client as paho

        self.host       = self.getParameter("Broker Host")
        self.port       = self.getParameter("Broker Port")
        self.keep_alive = self.getParameter("KeepAlive")
        self.topic      = self.getParameter("Topic")
        self.qos        = self.getParameter("Qos")

        self.mqttc = paho.Client()
        self.mqttc.on_message = self.onMessage
        self.mqttc.connect(self.host, self.port, self.keep_alive)
        self.mqttc.subscribe(self.topic, self.qos)

        self.mqttc.loop_forever()

    def onMessage(self, mqttc, obj, msg):
        self.logger.info("topic: " + msg.topic + ", payload: " + str(msg.payload) + ", qos: " + str(msg.qos) + ", retain: " + str(msg.retain))

    def onInput_onStop(self):
        self.onUnload()
        self.onStopped()
```


### Choregraphe で接続

![2015040402.png](https://qiita-image-store.s3.amazonaws.com/0/20418/6192fd09-8441-3774-20d6-78516d915af7.png "2015040402.png")


## Publisher 側

MQTT ブローカに "hello world" を飛ばすだけです。

```pub.py
# coding=utf8

import paho.mqtt.client as paho

mqttc = paho.Client()

mqttc.connect("test.mosquitto.org", 1883, 60)
mqttc.publish("my/topic/pepper5", "hello world", 1)
```


## 動作確認

### Subscriber を実行

Choregraphe でプログラムを実行し、メッセージの受信待機状態になります。


### Publisher を実行

ターミナルから Publisher を実行します。

```bash
$ python pub.py
```


### 結果表示

Publisher -> Broker -> Subscriber とメッセージが伝わり、Subscriber 側である Choregraphe のログビューアに内容が表示されます。

![2015040403.png](https://qiita-image-store.s3.amazonaws.com/0/20418/f74e7fe0-9851-18a7-388d-e86726b76e74.png "2015040403.png")


## 動作確認2

試しに Subscriber 側でのメッセージ受信時の処理を下の形に変えてみると、Pepper 君がしゃべってくれます。

```python
    def onMessage(self, mqttc, obj, msg):
        tts = ALProxy("ALTextToSpeech")
        tts.say(msg.payload)
```


## 感想

* Publisher / Subscriber と両方やりましたが、Publisher 側としては各種情報を定期的に飛ばす、Subscriber 側としてはコントロールの情報を取得して処理を変える、という感じが　Pepper 君では使いやすそうかな。
* 今回は試していないですが、一対多、多対一という使い方も面白そうですね。