Edited at
slackDay 2

SlackのreactionをリアルタイムなON/OFFスイッチとして使う

More than 3 years have passed since last update.

Slackはいわゆるチャットツールなのですが、他のサービスと比べると外部連携に力を入れているようで(個人の感想です)、APIが充実しているので触っていて面白いです。

この記事ではAPIの中でもreaction関連の部分にフォーカスしてみます。


この記事でやること


  • reactionの特徴を考える

  • reactionをスイッチとして使ってみる


その前にreactionとは何か?

reactionというのは、いわゆるFacebookの「いいね!」ボタンみたいなものを、各メッセージに後付でつけたり消したりすることができる機能です。

画像で説明すると、メッセージの下の「親指上げる絵文字」のところがreactionです。

2015-12-02_055330.png

詳しい説明はこちら。Slackで、投稿に対して絵文字で「いいね!」などのリアクションが返せるようになった


reactionはどう使うと効果的か

reactionは、他のメンバーから各記事に「いいね」をもらったり投票したりするのに使うのが一般的です。それ以外の用途に使おうと思った場合、まずreactionの特徴から考えるのがよさそうです。


  • ボタンを押すだけなので、意思表示しやすい(メッセージを打たなくて良い)


    • 一度押すと+1で、もう一度押すと-1(マイナス1)になる



  • SlackのReal Time Messaging APIだと、リアルタイムにreaction ON/OFFのイベントがあがってくるので、BOTがすばやく反応できる

  • そのチャンネルの議論とは異なるメッセージのやりとりを、reaction側に寄せることができる


    • BOTもメッセージ投稿せずにreactionをつけたり外したりできる



  • 最初にメッセージにreactionを付与するのが結構面倒


    • 一度つけられたreactionへの操作は超楽



上記を元に考えると、


  • 何かのON/OFFスイッチとしてreactionを利用する

  • reactionはなんらかのメッセージをキーに、BOTに付与してもらう

というアイデアを思いつきました。


SlackでLEDチカチカ

何をON/OFFさせるのか考えたのですが、リアルタイムON/OFFといえば自作電子回路のLEDをチカチカさせるのが便利さが伝わりやすそうです。

便利さを強調するために、iPhone上のSlackから、BOT経由で、小型Wifiモジュール ESP-WROOM-02を利用した電子回路のLEDをチカチカさせてみます。両方場所選ばないので、どこでもLチカが簡単に実現できます(今回は電源部分だけ有線です)


準備(Slack BOT側)

SlackのBOTのプログラムは、slappyのv0.6.0を利用しました。

参考記事:Slappy - 簡単にslackのbotを作れるgemを作った

BOT用のスクリプトを本体から独立したDSLで記述できるところと、Slack RTMイベントのフックがサポートされているところが超便利です。

今回は、SlackのRTMイベントのreaction_added event, reaction_removed eventをフックして、+1されたらLED点灯、-1されたらLED消灯としています。

一部そのままでは動かなかった部分(lib/slappy/listeners/concerns/validatable.rb)と手抜きしたかった部分(lib/slappy/event.rb)を改造しています。

(2015/12/4追記:v0.6.1で以下の2項目について採用されましたので、v0.6.1を利用する場合は下記パッチは不要です。コメント欄参照)


lib/slappy/listeners/concerns/validatable.rb

module Slappy

module Listener
module Validatable
include Slappy::Debuggable

attr_accessor :pattern

def valid?(event)
unless time_valid?(event)
Debug.log 'Event happend in before start time'
Debug.log event.ts
Debug.log Slappy.client.start_time
return false
end

target = event.send(target_element)
unless target
Debug.log 'Target is nil'
return false
end

event.matches = target.match pattern
unless event.matches
Debug.log "Target is not match pattern(#{pattern})"
return false
end

true
end

private

def time_valid?(event)
# eventによってはtsがない場合があるのでその場合は無視
return true unless event.has_key?(:ts)
event.ts > Slappy.client.start_time
end
end
end
end



lib/slappy/event.rb

module Slappy

class Event
extend Forwardable
include Debuggable

attr_accessor :matches

def_delegators :@data, :method_missing, :respond_to_missing?

def initialize(data)
@data = Hashie::Mash.new data
end

def text
@data['text'].to_s
end

def channel
SlackAPI::Channel.find(id: @data['channel']) ||
SlackAPI::Group.find(id: @data['channel']) ||
SlackAPI::Direct.find(id: @data['channel'])
end

def user
SlackAPI::User.find(id: @data['user'])
end

def ts
Time.at(@data['ts'].to_f)
end

def reply(text, options = {})
options[:text] = text
options[:channel] = channel
Messenger.new(options).message
end

def reaction(emoji)
result = ::Slack.reactions_add name: emoji, channel: @data['channel'], timestamp: @data['ts']
Debug.log "Reaction response: #{result}"
end

def bot_message?
@data['subtype'] && @data['subtype'] == 'bot_message'
end

# @dataの内容を外で直接扱いたい(手抜きしたい)
def data
@data
end
end
end


BOTスクリプトは、slappy newした時に作成される、slappy-scripts/example.rbを直接書き換えました。

ESPSERVERのところは、次に立てるWifiモジュールのIPアドレスを入れてください。

ここではローカルにあるPCからSlackにアクセスして、同じくローカルネットワーク内にあるWifiモジュールとプライベートIPで接続する想定にしていますが、グローバルIPがあれば世界中どこでもつながります。

BOT_USERIDのところは、BOTがreactionを付与する際にもイベントがあがるので、BOTだったらLチカさせないようにする必要があるのですが、BOTかどうかの判定がイベントであがってこないので、BOTのID(xoxx-~のIDではなくて、UxxxxxxxというBOTのユーザIDとして付与されるID)を調べて入れてください。

(イベントあがってきたときのeventオブジェクトの内容をp event等でコンソールにdumpすると出てくるuserパラメータの値になります。)


slappy-scripts/example.rb

require 'net/http'

require 'uri'

ESPSERVER = ##YOUR WIFI WEBSERVER IP##
BOT_USERID = ##YOUR BOT USERID##
BUTTON1 = 'red_circle'
BUTTON2 = 'large_blue_circle'

hello do
puts 'successfly connected'
end

hear 'Lチカ' do |event|
event.reaction BUTTON1
event.reaction BUTTON2
end

monitor 'reaction_added' do |event|
next if event.data["user"] == BOT_USERID
button =
case event.data["reaction"]
when BUTTON1; 1
when BUTTON2; 2
else 0
end
Net::HTTP.get(URI.parse(ESPSERVER + button.to_s + '/on')) if button>0
end

monitor 'reaction_removed' do |event|
next if event.data["user"] == BOT_USERID
button =
case event.data["reaction"]
when BUTTON1; 1
when BUTTON2; 2
else 0
end
Net::HTTP.get(URI.parse(ESPSERVER + button.to_s + '/off')) if button>0
end



準備(Wifi WEB Server側)

Arduino IDEにESP8266用のデータをダウンロードすると、スケッチの例として、ESP8266WebServer/HelloServerというプログラムを読み込むことが出来ます。

参考記事:技適済み格安高性能Wi-FiモジュールESP8266をArduinoIDEを使ってIoT開発する為の環境準備を10分でやる方法

今回は、HelloServerのプログラムを改造しました。http://##ipaddr##/1/onでLED1が点灯、http://##ipaddr##/2/onでLED2が点灯、onをoffに変えると消灯するプログラムになります。


helloserver.ino

#include <ESP8266WiFi.h>

#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

const char* ssid = ##YOUR SSID##;
const char* password = ##YOUR Wifi PASSWORD##;

ESP8266WebServer server(80);

const int led1 = 13;
const int led2 = 12;

void setup(void){
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
digitalWrite(led1, 0);
digitalWrite(led2, 0);
Serial.begin(115200);
WiFi.begin(ssid, password);

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(WiFi.localIP());

server.on("/1/on", [](){
digitalWrite(led1, 1);
server.send(200, "text/plain", "led1 on");
});
server.on("/2/on", [](){
digitalWrite(led2, 1);
server.send(200, "text/plain", "led2 on");
});
server.on("/1/off", [](){
digitalWrite(led1, 0);
server.send(200, "text/plain", "led1 off");
});
server.on("/2/off", [](){
digitalWrite(led2, 0);
server.send(200, "text/plain", "led2 off");
});

server.begin();
Serial.println("HTTP server started");
}

void loop(void){
server.handleClient();
}


Arduino IDEから、ESP-WROOM-02にプログラムを転送します。シリアルモニタを立ち上げて、WEBServerが立ち上がったことと、IPアドレスを確認してください。(IPアドレスは、準備(Slack BOT側)のBOTスクリプトに埋め込む必要があります)


動かそう

iPhoneとWifiモジュールに回路を組み込んだものを重ねてみました。

P1030266_2.jpg

画像だと伝わりにくいですが、「Lチカ」とメッセージを書くとbotがreactionを2つつけてくれます。そのreactionをそれぞれ押すと、下の回路の対応する赤LEDと青LEDが光る/消えるとなります。

P1030267_2.jpg

動画だとこういう感じです。

output_7.gif

「Lチカ」とメッセージを送った後、reactionが出てくるのが遅いのは、RTM APIではなくて、Slack WEB APIを使わないといけないため、1APIにつき1秒のリミットがあるからです。

output_12.gif

reactionを押すと、押した直後にLEDが点灯していますね。これぐらいだとわりと実用的に使えるのではないでしょうか。


まとめ

SlackとIoTは親和性高いんじゃないかと思いました。スマホから簡単に使えるので、中途半端なインターフェース作るくらいなら、Slackでまずはプロトタイプというのも選択肢に入りそうです。