HubotとSlackのDockerイメージ を使ってMQTTのPublishとSubscribeを実装してみます。Hubotのスクリプトはnpmパッケージをrequireしてプログラムを書くことができます。再利用性を考えるとコマンドは外部パッケージにした方がよいですが、カジュアルにscriptsディレクトリにデプロイして使うこともできます。MQTTブローカーに環境データをpublishするRaspberry Pi 2や、MQTTブローカーからメッセージをsubscribeしてLEDライトの電源を制御するBeagleBone Blackについては次回まとめようと思います。
ユースケース 今の気温が知りたい (Subscribe) Slackからbotに「今の気温は?」や「今の気温は?」に質問すると、MQTTブローカーからsubscribeしている環境データの最新の値を教えてくれます。
LEDライトをon/offしたい (Publish) Slackからbotに「ライト付けて」や「ライト消して」と指示すると、MQTTブローカーにpublishして植物育成LEDライトを付けたり消したりしてくれます。
プロジェクト 前回作ったプロジェクトにいくつか設定を追加しました。リポジトリはこちら です。
$ cd ~/node_apps/docker-hubot-slack $ tree ├── Dockerfile ├── README.md ├── docker-compose.yml ├── docker-compose.yml.default ├── redis └── scripts ├── hello.coffee └── mqtt_meshblu.coffee
Dockerfile DockerfileではDockerイメージのグローバルにhubotのパッケージをインストールしてあります。Yeoman を使って/app
ディレクトリにHubotプロジェクトを作成します。Dockerホストの作業ユーザーと同じuidのdocker
ユーザーにスイッチします。Yeomanのジェネレーターが作成した/app/package.json
に、今回使用するhubot-slack とmqtt のパッケージを追加してインストールします。
~/node_apps/docker-hubot-slack/Dockerfile FROM iojs:2.3 MAINTAINER Masato Shimizu <ma6ato@gmail.com> RUN mkdir -p /app WORKDIR /app RUN adduser --disabled-password --gecos '' --uid 1000 docker && \ chown -R docker:docker /app RUN npm install -g hubot coffee-script yo generator-hubot USER docker RUN yes | yo hubot --defaults && \ npm install --save hubot-slack mqtt
scripts/mqtt_meshblu.coffee MQTTクライアントはMQTT.js を使います。今回書いたrobot.respond
の正規表現では、botは最低限のコマンドしか理解できません。Rakuten MA の形態素解析を使ってもうちょっと賢く応答できるようにしたいです。
~/node_apps/docker-hubot-slack/scripts/mqtt_meshblu.coffee mqtt = require 'mqtt' opts = host: process.env.MQTT_HOST username: process.env.ACTION_1_UUID password: process.env.ACTION_1_TOKEN protocolId: 'MQIsdp' protocolVersion: 3 client = mqtt.connect opts client.subscribe process.env.ACTION_1_UUID sensor_data = '' client.on 'message' , (topic, message) -> payload = JSON .parse message sensor_data = payload.data commands = '気温' : 'temperature' '湿度' : 'humidity' '気圧' : 'pressure' units = '気温' : '℃' '湿度' : '%' '気圧' : 'hPa' module .exports = (robot) -> robot.respond /(気温|湿度|気圧)を(おしえて|教えて)$/i , (res) -> sensor = res.match[1 ] answer = if sensor_data retval = sensor_data[commands[sensor]] + ' ' + units[sensor] sensor + 'は ' + retval + ' です。' else 'データが取れません。:imp:' res.send answer robot.respond /ライトを(つけて|付けて|けして|消して)$/i , (res) -> on_off = switch res.match[1 ] when 'つけて' , '付けて' then 'led-on' when 'けして' , '消して' then 'led-off' else 'led-on' answer = if on_off == 'led-on' then 'ピカッ。' else 'カチッ。' message = devices: process.env.ACTION_3_UUID payload: on_off client.publish 'message' , JSON .stringify(message) res.send answer + ':flashlight:'
Subscribeした環境データを表示する robot.respond /ライトを(つけて|付けて|けして|消して)$/i , (res) ->
Raspberry PiはBME280から計測した環境データをJSON形式でMQTTブローカーにpublishしています。このbotでsubscribeしてメッセージを受信する度にグローバルのsensor_data
を更新します。botが気温や湿度の質問を受けたときに、受信しているメッセージを返します。
PublishしてLEDライトのオンオフの指示を出す robot.respond /ライト(つけて|付けて|けして|消して)$/i , (res) ->
「つけて」の場合は「on」、「けして」の場合は「off」の値をpayloadに入れてメッセージをMQTTブローカーにpublishします。このメッセージはBeagleBone Blackがsubscribeしています。on/offに応じてUSB電源連動タップを接続しているUSBハブのポートの電源を制御します。これだとリモートから本当に植物育成LEDライトが点灯したかわからないのが課題です。Webカメラとか付けたらいいかも。