36
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

slackAdvent Calendar 2015

Day 2

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

Last updated at Posted at 2015-12-01

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でまずはプロトタイプというのも選択肢に入りそうです。

36
39
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
39

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?