mosquittoでMQTTとWebSocket両方に対応させる

久々にMQTTブローカーサーバ使ってたら、mosquittoがMQTTとWebSocketに対応していたのでメモ

何が嬉しいか

今まではMQTTとWebSocketをバインドするためにNode.jsなどを使い、MQTTからWebSocketへ変換していました。例えばこんな感じに。 まぁこの頃はSocket.IOとか使ってたので、すでに古いのですが・・・

// WebSocket -> MQTT
io.sockets.on('connection', function(socket) {
    socket.on('message', function(data) {
        // MQTTで送信
        client.publish(PUSH_LOCATION, JSON.stringify(data.value));
    });
});

// MQTT -> WebSocket
client.on('message', function (topic, message) {
     // WebSocketで送信
     io.sockets.emit('SYS_STATUS', message);
});

これがmosquittoをWebSocketに対応させることでNode.jsは必要なく、nginx + HTML + JSで済むようになります。

画面をデザイナーさんに頼むときにNode.js動かさないと画面作れなかったりしたんですが、HTML + JSだとデザインする方もファイルだけなのでかなり楽になるんじゃないかと思います。

mosquittoの設定ファイルの修正

対応しているmosquittoのバージョンはver1.4.2以降のようです。Ubuntuではバイナリがすでに対応済みなのでそれを導入しますが、デフォルトではWebSocketには対応していません。

$ sudo apt-get install mosquitto

Ubuntuでaptでインストールした場合、設定ファイルは /etc/mosquitto/mosquitto.confになります。

# Place your local configuration in /etc/mosquitto/conf.d/
#
# A full description of the configuration file is at
# /usr/share/doc/mosquitto/examples/mosquitto.conf.example

pid_file /var/run/mosquitto.pid

persistence true
persistence_location /var/lib/mosquitto/

log_dest file /var/log/mosquitto/mosquitto.log

include_dir /etc/mosquitto/conf.d

これに以下の行を追加して、WebSocketに対応するようにします。

listener 1883

listener 9090
protocol websockets

WebSocketに対応させるにはprotocol websocketsだけで良いみたいですが、その場合MQTTが動作しなくなります。 この例ではMQTTは1883ポート、WebSocketは9090ポートで動作します。

設定ファイルを書き換えたら、サービスをリスタートさせます。

$ sudo service mosquitto restart

mosquittoのログ(/var/log/mosquitto/mosquitto.log)を見てみると、起動時にMQTTとWebSocketの両方が動作しているはずです。

1453293506: mosquitto version 1.4.7 (build date Tue, 22 Dec 2015 12:47:28 +0000) starting
1453293506: Config loaded from /etc/mosquitto/mosquitto.conf.
1453293506: Opening ipv4 listen socket on port 1883.
1453293506: Opening ipv6 listen socket on port 1883.
1453293506: Opening websockets listen socket on port 9090.

HTML + JS の記述例

動作環境はnginxにHTML + JSです。まずはHTMLファイル。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>TEST</title>
    <script type="text/javascript" src="mqttws31.js"></script>
    <script type="text/javascript" src="client.js"></script>
</head>
<body>

</body>
</html>

mqttw31.jsは Paho MQTTのJavaScriptクライアントです。こちらからダウンロードします。

次にJavaScriptファイル(client.js)の例です。サーバアドレスにはmqtt://やws://などのスキーマは不要です。ポートにmosquitto.confで追加したWebSocketの9090を指定しています。

// Create a client instance
var client = new Paho.MQTT.Client("サーバアドレス", 9090 , "clientId" + new Date().getTime());

// set callback handlers
client.onMessageArrived = onMessageArrived;

// connect the client
client.connect({onSuccess:onConnect});

// called when the client connects
function onConnect() {
    // Once a connection has been made, make a subscription and send a message.
    console.log("onConnect");
    client.subscribe("PUBLIC/log/#");
}

// called when a message arrives
function onMessageArrived(message) {
    console.log('payload: ' + message.payloadString);
}

これで、他クライアントからMQTTでデータをブローカーサーバに送信すると、subscribeしていればデータを受信してペイロードを取得できます。

実際の動作としては、mqttw31.jsがMQTTクライアントとして公開されているので、WebSocketは関係なくて、ブラウザレベルでMQTTで接続できるんじゃないか?と思いますが、このMQTTクライアントは内部でWebSocketに変換しています。そのため、ブローカーがWebSocketに対応する必要があります。

これでNode.jsでサーバアプリ書かなくてもよくなるので、かなり楽になるんじゃないかなーと。。。

参考にしたサイト