Amazon Dash Buttonで出社する

この記事は出社芸アドベントカレンダーの18日目の記事です。


今日のアドベントカレンダーに登録した。
現在0:31。あと23時間半くらいある! 余裕だね! 

ちなみに夜開いてる喫茶店がなかったのでこの記事はHUBで書いてる。すごくうるさい。

出社時間をSlackに報告する

弊社は出社自由。リモートもOKで出社も自由。 (自分はリモートすると孤独で寂しかったりするので、旅行中以外は割と出社してる)

※詳細は出社芸アドベントカレンダー1日目出社自由の会社を作ったよ | rake enjoyをご参照。

でもルールがあって、何時ごろ出社するか(/どこで仕事するか)をSlackのチャンネルで報告する義務がある。

https://gyazo.com/5d218796a4343d1334ce0059c65973f4

リモートが多い時はこんな感じになる。

自由だ…。

◯◯時頃出社しますと報告するのが面倒になってきた

出社時刻をSlackでつぶやくだけで遅れたりすることで怒られるなどは全く無い。 この会社に入ってアラームを設定することが無くなった。
起きたら何時に出社するか決めてSlackで報告すればいい。

しかし、毎日、何時になるかといちいち考えたりするのすら面倒になってくる。
プログラマは怠惰な生き物。 あのラリー・ウォールも**怠惰(Laziness)**がプログラマの美徳だと名言している。

自動化しよう

朝起きて時計を確認、何時ごろに出社するか決めて、Slackアプリを開き、報告する。 このフローを自動化する。なるべく楽に。

作戦としては今流行りのAmazon Dash Buttonを使う。 押したらSlackへ何時に行くかつぶやく。

起きたらAmazon Dash Buttonを押すだけ。俺がデリバリーされる。

準備するもの

Amazon Dash Button

これはAmazonで買える。500円。安い。
対象商品の初回購入時が500円割引されるので実質タダ。

なお、ものによっては到着に時間がかかるものもあるので注意。

https://gyazo.com/518ab73560119267fa5e740036585f9f

とりあえず翌日届くレノアにした。

ローカルサーバ

Amazon Dash Buttonはローカルネットワークに接続し、ボタンを押すとローカルネットワーク上にブロードキャストされる。
そのブロードキャストがAmazon Dash Buttonから来たかをMacアドレスで判断する。そうであれば任意のアクションを実行するだけ。
ボタンが押された時に任意のアクションをキャッチするのにローカルネットワーク上で動作する常時稼働サーバーが必要。
みんなのお家に眠っているラズベリーパイを使おう。

エンドポイント

任意のアクションをキャッチする場所が必要。 Slackのエンドポイントを直接作っても良いが、拡張性をもたせるため、IFTTTでエンドポイントを作る。
IFTTTのエンドポイントさえあれば、GmailでもGoogleカレンダーでも何にでも連携出来る。

実装する

処理は大きく見ると下記の様な流れになる

Amazon Dash Button ---> LocalServer ---> IFTTT ---> Slack

IFTTTとSlackを連携する

前述したとおり、Slackとの連携部分を作る。 無料のクラウドサービスIFTTTで作る。 もっと自由にやりたいならAWS Lambdaを使おう。

エンドポイントを作る

IFTTTでTriggerを作る Makerから自分でエンドポイントを作ることが出来る。
任意のサービスと連携したり、アクションとしてPostしたりもできる。

https://gyazo.com/b23e6ea97dd8a3d21619baf5cf43664c

これでエンドポイントが作られる。LocalServerはこいつを叩く。
event_nameは"press_button"にしてみた。

Slackとつなげる

どのチャネルに流すか、どのような内容をポストするかを設定できる。
自分は下記にように設定した。

https://gyazo.com/9d91bbc1016f27ca8e0acb19f0034c03

メッセージは特にテンプレートを作らず、渡した内容でそのままポストするようにした。 value1, value2, value3までパラメータをもたせられて、POSTのbody部にこれを指定してあげるとIFTTTが解釈してよしなに投げてくれる。

Amazon Dash Buttonを設定する

スマホのAmazonアプリを立ち上げる。 アカウントサービス > Dash端末 > 新しい端末をセットアップを選択。

アプリの指示にしたがって設定していく。

途中で商品の種類を選択する画面が出る。 右上の閉じるボタンを押してセットアップを終了する。

https://gyazo.com/dbf6d2e1604156b6f28689694c246d85

ここで終了してしまえばボタンが押されても発注されることはない。

ボタンが押される度にレノアが注文されることを防ぐ。

ボタンのMACアドレスを取得

後述するツール使っても良いが、手っ取り早いのはtcpdumpコマンド。
ローカルネットワーク上のARPパケットをキャプチャする方法が多いけれど。BOOTP(DHCP)のパケットをフィルタしてしまおう。

端末上でsudo tcpdump | grep BOOTP/DHCPを走らせている間にボタンを押す。

すると下記のような行が抽出される。

03:14:56.824982 IP 0.0.0.0.bootpc > 255.255.255.255.bootps: BOOTP/DHCP, Request from 12:34:56:78:90:ab (oui Unknown), length 261

MACアドレスをメモ。(上の例だと12:34:56:78:90:ab)

ネットワークのデバイス名を取得

ifconfigで取得する

$ ifconfig
lo        Link encap:ローカルループバック
          inetアドレス:127.0.0.1  マスク:255.0.0.0
          inet6アドレス: ::1/128 範囲:ホスト
          UP LOOPBACK RUNNING  MTU:65536  メトリック:1
          RXパケット:67300 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:67300 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:1
          RXバイト:5282713 (5.2 MB)  TXバイト:5282713 (5.2 MB)

wlp2s0    Link encap:イーサネット  ハードウェアアドレス 88:53:2e:a7:bf:b1
          inetアドレス:192.168.43.29  ブロードキャスト:192.168.43.255  マスク:255.255.255.0
          inet6アドレス: fe80::8a53:2eff:fea7:bfb1/64 範囲:リンク
          UP BROADCAST RUNNING MULTICAST  MTU:1500  メトリック:1
          RXパケット:500992 エラー:0 損失:0 オーバラン:0 フレーム:0
          TXパケット:429394 エラー:0 損失:0 オーバラン:0 キャリア:0
          衝突(Collisions):0 TXキュー長:1000
          RXバイト:371972200 (371.9 MB)  TXバイト:74863446 (74.8 MB)

eth0, wlan0のような伝統的なデバイス名が出力されると思っていたら違った。 wlp2s0 最近のLinuxカーネルは名前の付け方が変わったのか? これが無線で通信する際のデバイス名なのでメモしておく。

ボタン押したら何かするように実装

各言語便利なライブラリが幾つか揃っているちょっとググったら色々あったのでお好きなものを。

なお、自分がRubyをよく使うのでdashed使って実装する。

Rubyのライブラリdashedを使って実装する

dashedをrequireして下記のブロック内で処理を書く。

Dashed::Button.new(MACADDRESS, DEVICENAME).on_press do
  # ボタン押されたらここの処理が走る
  puts 'ボタンが押されたよ'
end

MACADDRESS, DEVICENAMEは前にメモしたマックアドレスとデバイス名を文字列で。

sudo権限で走らせる必要があるので注意

エンドポイントへ通信させる

IFTTTのエンドポイントを作って、Slackへ投げるアクションのひも付けまで行っているので、 あとの作業はIFTTTのエンドポイントにPOSTするだけ。

エンドポイントは https://ifttt.com/services/maker/settings のページに表示されるURLへリンク直打ちすると、下記のようなページが表示される。 https://gyazo.com/47a133a890ffd039c76ea34bac9e4039

POSTのbody部にvalue1, value2, value3のパラメータを含める。
それぞれメッセージとユーザ名、アイコンのURLとして利用する。

RubyでのHttpsの通信にはnet/httpsを使った。

Dashed::Button.new(MACADDRESS, DEVICENAME).on_press do
  uri = URI.parse(ENDPOINT)
  http = Net::HTTP.new(uri.host, uri.port)
  http.use_ssl = true
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
  req = Net::HTTP::Post.new(uri.path)
  req.set_form_data(value1: message, value2: USERNAME, value3: ICONURL)
  http.request(req)
end

このような実装になる

つぶやく内容をいい感じにする

Gistにアップしてみた。

gemがインストールされていて、IFTTTで発行されたキーを引数に渡せば動くはず。

起きてすぐはぼーっとしたりしてるので1.5時間後に出社するよう設定した。 あと人がつぶやいたっぽくするために時間を四捨五入するとかそういう処理入れている。

出社する

ボタンを押して出社報告する。

$ sudo ruby yamadash.rb IFTTT_KEY のようにコンソールで実行するとキャプチャを開始してくれる。
IFTTTのkeyはMakerのurl中に含まれる文字列だ。 この状態で放置してればいい。

ボタンを押してみる

https://gyazo.com/788190d8d7609951fac678edc624ea7d

成功した。

押してから数秒のラグある。
IFTTTがすぐに動いてくれない時もあるので、投稿されないからといって連打は厳禁。
このへんの連打対策もいれてもよさそう。

みなさんも出社報告が面倒であればAmazon Dash Buttonに任せてみてはいかがだろうか。