まだプログラマーですが何か?

プログラマーネタ中心。たまに作成したウェブサービス関連の話も https://twitter.com/dotnsf

タグ:mosquitto

自分で作って公開しているサービスの中で使うために MQTT over WebSocket サーバーが必要になり、DockerHub の eclipse-mosquitto イメージを使って同環境を構築したので、その手順を紹介します。
2023040900



【MQTT over WebSocket とは】
「WebSocket(HTTP) プロトコルで実現する MQTT」です。MQTT ブローカーに対して Publisher や Subscriber の機能をウェブのクライアント(=ブラウザ)から使いたい場合に、ウェブクライアントから直接 MQTT を使うことはできませんが、HTTP ベースである WebSocket 経由で使うことができます(そのためのライブラリも公開されています)。このような「WebSocket 対応した MQTT 」が MQTT over Socket で、そのような MQTT ブローカー環境を構築するための手順を以下で紹介しています。


【事前準備】
今回は MQTT ブローカーとして DockerHub から公式イメージとして公開されている eclipse-mosquitto を使い、これを MQTT over WebSocket 対応させます。 というわけで eclipse-mosquitto イメージが対応した docker 環境(linux/386, linux/amd64, linux/arm/v6, linux/arm64/v8, linux/ppc64le, linux/s390x)を事前にご用意ください。


また以下のような mosquitto.conf ファイルが必要です。これは mosquitto の動作設定用ファイルなのですが、これとは別の設定が必要な場合は、それらの設定の最後にこの4行の内容を追加して mosquitto.conf ファイルを用意してください(ここでは /tmp/mosquitto.conf というファイルパスで作成したものとします):
listener 1883
allow_anonymous true
listener 11883
protocol websockets

※ちなみにこの4行が意味する設定内容は以下の通りです。この設定を変える場合は(数値などを)適宜変更してください:

  • 1883 番ポートで MQTT を送受信する(変更せずこのまま)
  • 11883 番ポートで MQTT over WebSocket を送受信する(使っていないポート番号なら任意)
  • 認証無し

docker コンテナの起動だけであれば以上の準備でいいのですが、後述の動作確認までを行う場合は Node.js の実行環境が必要になります。必要な場合は Node.js のインストールまで済ませておいてください。



【起動】
ここまでの準備ができていれば起動は簡単です:
$ docker run -d -p 1883:1883 -p 9001:9001 -p 11883:11883 -v /tmp/mosquitto.conf:/mosquitto/config/mosquitto.conf --name mosquitto eclipse-mosquitto

外部に公開するポートとして 1883, 9001, 11883 を指定し、用意した mosquitto.conf ファイルを使って eclipse-mosquitto イメージを実行しています。


【動作確認】
以下のサンプルソースコードを使って動作確認します:
https://github.com/dotnsf/MoWS

このアプリケーションそのものは「簡易 SNS」です。タイトルとメッセージを編集&送信すると、その内容を一覧画面で確認できます。一覧画面をリロードするとその時点までに送信されたメッセージの一覧が表示されますが、一覧表示後に新しいメッセージが送信された場合、通常のアプリであればリロードするまでは新しいメッセージは表示されないのですが、このサンプルアプリでは MQTT over WebSocket を併用することで新しいメッセージが自動的に画面最上部に追加されるようになっています。


実際に動かしてみましょう。"git clone" 等でソースコードをダウンロードします。そしてルートフォルダ直下にある .env ファイルをテキストエディタで開き、以下の内容に書き換えて保存します:
MOWS_URL=ws://xxx.xxx.xxx.xxx:11883
MQTT_URL=mqtt://xxx.xxx.xxx.xxx
MQTT_PORT=1883
MQTT_TOPIC=yellowmix/mytest/topic

この内容の、"xxx.xxx.xxx.xxx" 部分は上で起動した MQTT ブローカーコンテナの IP アドレス、11883 は同ブローカーで MQTT over WebSocket が待ち受けるポート番号、1883 は MQTT が待ち受けるポート番号です。また MQTT_TOPIC には適当なトピック文字列を指定してください(よくわからなければこの例の内容そのままでも構いません)。

※なおデフォルト状態の MOWS_URL は "wss://test.mosquitto.org:8081" と設定されているので、プロトコル部分も "wss" から "ws" に変更する必要がある点に留意してください。

そして動作確認用アプリケーションを起動します:
$ npm install
$ node app

アプリケーションは 8080 番ポートで起動します。ウェブブラウザを2つ(同じブラウザの別ウィンドウでも可)を開いて、1つは一覧画面である "http://localhost:8080/" にアクセスします:
2023040901


そしてもう1つは編集画面である "http://localhost:8080/edit" にアクセスします:
2023040902


編集画面内の「タイトル」欄と「本文」欄に適当な文字列を入力します。最後に「送信」ボタンをクリックします:
2023040903


全て正しく動作していると、一覧画面をリロードしていなくても、編集画面で入力されたメッセージが一覧画面に表示されているはずです。編集画面に入力された値はバックエンド側で MQTT パブリッシュされ、MQTT over WebSocket でサブスクライブしていた一覧画面に内容とともに通知され、リロードしていなくてもその内容が表示できています:
2023040904


同様にして編集画面から送信するたびに一覧画面が更新されていく様子が確認できます:
2023040905


ちなみに送信されたメッセージはアプリケーションが起動している間はメモリ内に保存されているので、一覧画面をリロードするとそれまでに送信されたメッセージが新しい順に並ぶ様子も確認できます(データを適当な DB に永続保存して、そこから読み出すように改良すれば一応の SNS っぽくなると思います)。MQTT over WebSocket を使って一覧が自動更新される簡易 SNS が実現できている様子を確認できているはずです。


【まとめ】
趣味アプリの1つとして SNS っぽいものを作っているのですが、その中で要件としてでてきた「一覧の自動更新」機能を実現するための手段として MQTT over WebSocket を使う例を紹介しました。ウェブブラウザの JavaScript で実装された MQTT over WebSocket ライブラリを使って MQTT サブスクライブを実装することで比較的簡単に実現できることがわかりました。


最近は多くのクラウド業者が IoTMQTT との連携をアピールしています。IBM を含めて各社が「いかに簡単に IoT データを扱う/応用することができるか」を競っている感じです。

この点で IBM の強みの1つが Node-RED フローエディタだと思っています。Bluemix に統合されたこの GUI エディタは MQTT サーバー(ブローカー)との接続を簡単に行い、データを集め、保存する仕組みを簡単に提供することができます。MQTT ブローカー/クライアントの Mosquitto といい、この Node-RED といい、IoT にもオープンソース製品が多くの場面で使われるようになってきて、更なる広まりを見せているように感じます:
2015082602


IBM の場合、この Node-RED をうまく Bluemix に合わせてカスタマイズして提供しており、Bluemix 内ではすぐに使えるようになっており、また Bluemix の各サービスと簡単に組み合わせて使えるような形で提供されています。


ただ Node-RED そのものはオープンソースで提供されているものです。他のクラウドインスタンスやオンプレミスサーバー環境でも(Bluemix 用の拡張がされていない素のエディションを)動かすことが可能です。つまり IBM 以外の業者のクラウド環境内で Node-RED を使った IoT アプリ開発環境を構築することだってできるわけです。


というわけで、今回のブログエントリでは SoftLayer や AWS、IDCF、オンプレミスなどの(クラウド)サーバー環境内で Node-RED を使って IoT アプリ開発環境を構築する手順を紹介します。


まず最初に Bluemix と IBM IoT Foundation を使った場合の IoT アプリ開発環境のシステムトポロジーを確認しておきます。必要になるサーバーとしては各種センサーデバイスからの情報を集約する MQTT ブローカーと、Node-RED が稼働する Node.js アプリケーションサーバーです。Bluemix 環境の場合、前者は IBM IoT Foundation が提供する quickstart サーバーを無料で使うことができます(つまり構築不要です)。後者は Bluemix のボイラープレートを使うことで Node-RED が動く状態まで含めて簡単に構築できてしまいます。なお収集したデータを保存しようとすると別途データベースサーバーを用意する必要がありますが、Bluemix であればデータベースも簡単に追加してバインドすることが可能です(今回はデータベースを使わない環境を前提とします):
2015082601


これと同じ環境を Bluemix を使わずに構築することを考えると、(物理的には1台のマシンでも構いませんが)上記の MQTT ブローカーと Node.js の2サーバーを手動で用意することになります:
2015082602


具体的には MQTT と Node-RED それぞれの環境を用意する必要があります。1台または2台のサーバーを用意し、それぞれのサーバーインスタンスに MQTT ブローカーおよび Node-RED 環境を構築します。それぞれの手順は(CentOS サーバーの場合であれば)以下の記事を参照ください:
ラズベリーパイにオープンソース MQTT の Mosquitto をインストールする (←ラズベリーパイだけでなく CentOS の場合のインストール方法も記載しています)
CentOS に Node-RED をインストールする


まずは MQTT ブローカーを起動しておく必要があります。MQTT ブローカー(Mosquitto サーバー)を導入したマシン上で以下のコマンドを実行するなどして Mosquitto サービスを動かしておきます:
# service mosquitto start

次に Node-RED を導入したサーバーで Node-RED を起動します:
2015082603


起動した Node-RED にブラウザでアクセスします。Node-RED はデフォルトでは 1880 番ポートで起動するので、 http://(Node-RED サーバー):1880/ でアクセスするとフローエディタの画面が開きます:
2015082604


そして下図のような、MQTT インプットと Debug アウトプットを繋げただけのシンプルなフローを記述します:
2015082608


MQTT インプットの属性は以下のようにします。Broker には Mosquitto を導入したサーバーの 1883 番ポートを指定します。Topic はなんでもいいのですが、ここでは "top/001" と指定しています(後で実行するコマンドで指定することになる文字列です)。準備ができたらデプロイして実行状態にします:
2015082605


これで環境は出来上がりました。では正しく動いているかどうかを確認してみましょう。
別途 Mosquitto クライアントを導入したマシン(これも同一マシンでもかまいません)から以下のコマンドを実行して、MQTT ブローカーにメッセージをパブリッシュします:
$ mosquitto_pub -h (MQTT ブローカーサーバー) -t "top/001(上記 Node-RED で指定した Topic 属性と同じ文字列)" -m "Hello."

2015082606


すると、Node-RED 画面の debug タブには -m オプションで指定された文字列が表示されるはずです。つまり MQTT ブローカーの top/001 トピックに送信されたメッセージを、Node-RED から正しく取得することができたことになります:
20150824_nodered



ちゃんと動きました。Node-RED は Bluemix や IBM IoT Foundation がなくても、普通の(?) MQTT 環境の中でも動くことが確認できました。


・・・とはいえ、Bluemix + IBM IoT Foundation 環境で Node-RED を使ったことのある者として言わせていただくと、ここまでの環境を整えないと使えないわけです。また現実的には取得したデータをデータベースに格納しようとすると、Bluemix 環境のように簡単にはいきません。動くか動かないかでいうと動きますが、その準備のためのハードルはまだまだ高いように感じています。

IoT アプリ開発環境を検討する上で IBM Bluemix + IBM IoT Foundation + Node-RED がいかに簡単で便利なのか、を改めて再確認するような実験になったとも感じました。




 

以前のブログエントリでオープンソース MQTT 環境である Mosquitto の導入方法を紹介しました。このブログエントリではラズベリーパイ用と CentOS 用の紹介をしていますが、Mosquitto 自体には Windows などのバイナリも用意されていて、多くの環境で使えます:
ラズベリーパイにオープンソース MQTT の Mosquitto をインストールする


この Mosquitto を使って、IBM IoTF(IoT Foundations) 環境に用意されている QuickStart と呼ばれる MQTT ブローカーに任意のメッセージデータを送る方法を紹介します。センサーシミュレータなどを使って QuickStart に送られたデータを集めて取り出して加工して・・・という作業は Node-RED 環境があれば簡単ですが、その前段になるデバイスから QuickStart にデータを送るにはどうするか?という手段の紹介です。今回は MQTT クライアント(パブリッシャー)を使った例を紹介します。


準備として、まずは上記のリンク先の情報から、Mosquitto のパブリッシャー(mosquitto_pub)をインストールする所までは済ませておいてください。今回は mosquitto_pub を使って IoTF QuickStart にデータを送信します。

次に、IoTF QuickStart に送られてきたメッセージデータを確認するための環境を整えておく必要があります。IBM Bluemix の IoT Foundations Starter ボイラープレートや Node-RED Starter ボイラープレートを使って、Node-RED 環境を用意してください。この辺りの詳しい手順がよく分からない場合はこちらを参照してください:


Node-RED 環境ができたら、次のような IBM IoT ノードと Debug ノードをつなげただけの、シンプルなフローを作成してください:
2015072701


IBM IoT ノードをダブルクリックし、このような属性値に設定します。Authentication を "QuickStart" に、Input Type を "Device Event" に、そして Device Id には任意のユニークな文字列(下の例では "91a19d112233" にしていますが、同じものを使わないでください。実際にはネットに接続された機器の MAC アドレスを想定しています)を入力します。最後に Name に適当な名前を入力して OK をクリックします:
2015072702


Debug ノードの属性は以下のようにします。Output はデフォルトの payload のままでも実用的にはいいのですが、今回は送られてくるメッセージ全体を確認したいので "complete msg object" に変更して OK をクリックします。最後に "Deploy" をクリックして、デプロイまで済ませておきます:
2015072703


これで Device Id が(今回の例であれば) "91a19d112233" に設定されたデバイスから QuickStart に送られてくるデータを取得してデバッグタブに表示する、というアプリが動いている状態になりました。

では Mosquitto を使って、そのようなデータを QuickStart にパブリッシュしてみます。Mosquitto を導入した環境にログインし、ターミナルのプロンプトから以下のようなコマンドを実行します:
$ mosquitto_pub -h quickstart.messaging.internetofthings.ibmcloud.com -t "iot-2/evt/myeventtype/fmt/json" -m '{"d":{"name1":"stringValue","name2":10}}' -i d:quickstart:MyDevice:91a19d112233

このコマンドは、
 (1) quickstart.messaging.internetofthings.ibmcloud.com という MQTT ブローカーに対して、
 (2) "iot-2/evt/myeventtype/fmt/json" というトピックを指定し、
 (3) '{ "d": { "name1":"stringValue", "name2": 10 } }' という JSON 形式のメッセージを、
 (4) d:quickstart:MyDevice:91a19d112233 というクライアント ID で
パブリッシュする、という処理内容のコマンドです。

※ちなみに IoTF では送信メッセージは '{ "d": { (ここが実際の送信内容) } }' という JSON 形式で送付することを推奨しています。

2015072704


このコマンドを実行した直後、Node-RED アプリのデバッグタブにメッセージが表示されるはずです! 実行したパブリッシュコマンドのメッセージが届いた証拠です:
2015072705


ここで届いたメッセージはこのような内容になっているはずです:
{
 "topic": "iot-2/type/MyDevice/id/91a19d112233/evt/myeventtype/fmt/json",
 "payload": {
  "d": {
   "name1": "stringValue",
   "name2": 10
  }
 },
 "deviceId": "91a19d112233",
 "deviceType": "MyDevice",
 "eventType": "myeventtype",
 "format": "json",
 "_msgid": "6e152038.91eae" 
}

(3) で指定したメッセージは、"payload" の中身として届けられています。また (2) で指定したトピックは "topic" と、"eventType" の値として表示されています。また (4) で指定したクライアント ID は "deviceId""deviceType" として届いていることもわかります。"deviceType" と "eventType" はパブリッシュする側で任意に設定できる、デバイスとイベントの分類用文字列です。


ということは、上記の mosquitto_pub コマンドで実行した MQTT パブリッシュ処理に相当するコマンドを quickstart.messaging.internetofthings.ibmcloud.com に対して実行することで QuickStart にメッセージを送ることができる、ということが分かりました。QuickStart にメッセージを送ることができれば、後は Node-RED を使って便利に処理できます。

このコマンドをプログラミング言語から実行するにはどのようにすればよいのか、それは別途紹介させていただくつもりです。
 

IoT アプリケーションを作っていると、ローカルで MQTT 環境を使いたくなる時があります。

Mosquitto は、そんなオープンソースな MQTT のコントリビューションです。Windows や Mac 向けのバイナリも用意されているようですが、自分は Linux(ラズパイやCentOS) で使えると便利なので Linux 用の環境構築手順を紹介します。

まず、ラズパイだと話が早く、このコマンドを入力するだけで MQTT のブローカーが導入できてしまいます:
$ sudo apt-get install mosquitto

MQTT のパブリッシャーやサブスクライバーといったクライアントコマンドを使う場合は、更にコマンドを実行します:
$ sudo apt-get install mosquitto-clients


ブローカーは mosquitto というサービスとして導入されるので、service コマンドで他のサービス同様に扱うことができるようになります:
$ sudo service mosquitto status


一方、CentOS の場合は少し準備が必要です。インストールそのものは yum を使うので、まずは root でログインしてリポジトリを導入します:
# cd /etc/yum.repos.d
# wget http://download.opensuse.org/repositories/home:/oojah:/mqtt/CentOS_CentOS-6/home:oojah:mqtt.repo

リポジトリが準備できたら yum でインストールします。これはブローカーのインストールコマンドです:
# yum install mosquitto

パブリッシャーやサブスクライバーなどのクライアントコマンドをインストールする場合はこちらのコマンドを(も)実行します:
# yum install mosquitto-clients

インストール後は、このコマンドでブローカーのサービスが起動します。ちなみに TCP と UDP の 1883 番ポートを空けておく必要があります:
# /usr/sbin/mosquitto

まあどちらも簡単でした。これでローカル環境に MQTT ブローカーの構築ができてしまいました。



最後に動作確認をしてみます(動作確認には MTQQ クライアントコマンドを導入した環境が必要です。MQTT ブローカーと同じマシンでも異なるマシンでも構いません)。

MQTT ブローカーが稼働している状況で、MQTT クライアントコマンドの使えるターミナル(やコマンドプロンプト)を2つ用意します。1つがパブリッシャー(サーバー)、もう1つがサブスクライバー(クライアント)となります。

まず1つのターミナル内で MQTT サブスクライバー(クライアント)を起動します。その際に -h オプションで MQTT ブローカーが稼働しているホストを、-t オプションでトピック文字列をそれぞれ指定します。起動後はプロンプトが戻らず、(Ctrl+C で終了するまで)待ち続けます:
# mosquitto_sub -h 192.168.0.XXX -t "top/ic001" -v

次にもう1つのターミナル内で MQTT パブリッシャー(サーバー)を起動します。起動時に -h オプションでサブスクライバーと同じ MQTT ブローカーホストを、-t オプションでサブスクライバーと同じトピック文字列をそれぞれ指定します。また -m オプションでメッセージ(この例では "Hello, World.")を指定します:
# mosquitto_pub -h 192.168.0.XXX -t "top/ic0t01" -m "Hello, World."
# mosquitto_pub -h 192.168.0.XXX -t "top/ic001" -m "Hello, World."

成功するとパブリッシャー側はすぐにコマンドプロンプトが戻って終了しますが、サブスクライバー側には送信されたメッセージが表示され、そのまま次のコマンドを待ち続けるはずです:
# mosquitto_sub -h 192.168.0.XXX -t "top/ic001" -v
top/ic001 Hello, World. ←パブリッシャーから送られたこれがサブスクライバー側に表示される

動作確認もできました。3台(ブローカー、サブスクライバー、パブリッシャー)の役割分担も分かりましたね。



(参考にしたサイト)
http://flyerback.blogspot.jp/2014/04/mqtt-broker-mosquitto-amaazon.html


このページのトップヘ