Slackからラズパイを使って遠隔地の写真を撮れるようにした話

こんにちは、Misocaのとよし(@toyoshi)です。

この記事は、Misoca Advent Calendar 2017 の19日目の記事です。

前はちょっとした作業の自動化の話をしたのですが、今回も面倒な作業を自動化する話を書きます。
タイトルのとおり遠隔で写真がとれるようにした話なのですが、私はWebカメラといえばケンブリッジ大学のどこかの研究室のコーヒー残量をチェックしたことがある世代です。あれからもう24年ぐらい経っているようです。「まじで?」と思った人はこの記事にいいねしてください。会社のアドベントカレンダーのKPIはいいね数です。

さて、本題を始めます。

やったこと

こういうのを作って(手前がラズベリーパイです)

IMG_0493.JPG

こういう結果が得られるようにしました。

raspberrypi.png

toyoshi take photoとSlackに書き込むと写真が撮影されてSlackに投稿されます。

動機

どうしてこのようなものを作ったかというと、弊社に1日に1回ぐらい見るのだけどどうしてもオンライン化できずに目視しなければいけないものがあったからでした。
例えばこういうものだと思ってください。

  • コーヒー豆の残量
  • 壁に掲示しているカンバン(Misocaではまず紙でやってみて習慣化したらTrelloなどに移すことがあります)
  • リモートから会議室に人がいるかどうか確認したい

皆さんも外的な要因によってどうしても目視しないといけないものってありますよね?

準備

ラズベリーパイとカメラを買います。大人なのでコンプリートスターターキットというケースやLANケーブルとか電源もセットになってるやつを買いました。少し高いですがもう今月末には36歳なのでメリットしか感じませんでした。
ラズパイ用のカメラは初代の安いカメラと、v2という性能のいいカメラがありますが、今回は様子がわかればいいだけなので安い方を選びました。

方法

Raspberry Piのセットアップ

image.png
引用:https://www.raspberrypi.org/blog/introducing-pixel/

コンプリートキットなのでOSインストール済みのSDカードが付属しています。自宅のテレビに繋いで電源を入れたらいきなりLinuxのデスクトップ環境が立ち上がって驚きました。ゲームを確認したらマインクラフトが入っていたので遊びました。ScratchやPythonも入っていていきなりプログラミングも楽しめます。こどものころこんなものがもらえたらすごく嬉しかっただろうなと思いました。

カメラ

IMG_8535.JPG

むき出しの状態で売っています。専用ケースも売っていますがカメラの価格より高いので諦めました。セロファンテープで固定しています。

コマンドラインからのコマンド

接続したカメラで写真を撮影するにはraspistillコマンドを使います。

raspistill -o cam.jpg

てな感じで写真をお手軽に撮影できます。

参考:raspistill - Raspberry Pi Documentation

Slackからの命令受付と、投稿

Slackからラズパイに命令するにはRubotyを使いました。RubotyはRuby製のbotフレームワークです。Rubotyを使うと簡単にSlackからの入力を受け取って返答するbotが作成できます

参考

今回だと写真を撮影し、RubotyからSlackのAPIを叩いて画像を送るだけです。写真を撮影するメソッドはこんな感じになります。

      def pi_camera_upload(message)
        message.reply('撮影してくるから、ちょっと待ってね') # 写真を撮影するのに1秒ぐらいかかるので返答
        Dir.mktmpdir do |dir|
          file_name = "#{dir}/image.png"

          begin
            system(`raspistill -rot 90 -t 500 -w 800 -h 800 -o #{file_name}`) # 90度回転させて、500ms後に800x800で撮影する。
          rescue
            message.reply('写真の撮影ができなかったよ')
            return
          end
        end
      end

これをgemにしてrubotyに読み込ませます。RubotyはGemで拡張して使うので、自分でGemとして公開するか、Githubにアップロードするか、Gistに公開する(GistでGemを公開する - Qiita)などして使います。
Gemとして公開しなくても、Gemfileで

gem 'pi-photo',  path: '/Users/me/path/to/pi-photo'

みたいにローカルファイルを指定することもできます。

自動起動・デーモン化

あとはRubotyを自動起動する設定が必要です。init.dに書いたりするのかと調べてみましたが、Systemdを使うととても簡単にサービス化できるようだったのでそれを採用しました。これを使うことにより再起動した時も、予期せぬ理由でプログラムが停止した時も自動でプログラムを起動してくれます。

下記のようなRubotyの起動スクリプトを用意しておく

#!/bin/bash

HOME=/home/toyoshi
PATH=$HOME/.rbenv/shims:$PATH
cd $HOME/ruboty

RUBOTY_ENV=production bundle exec ruboty --dotenv >/var/log/ruboty.log 2>&1

/etc/systemd/system/ruboty.serviceというファイルを作ってServiceとして定義。

[Unit]
Description = Ruboty Daemon

[Service]
ExecStart = /home/toyoshi/start_up_ruboty.sh
Restart = always
Type = simple

[Install]
WantedBy = multi-user.target

これでファイル名であるrubotyがサービスとして登録されるので、有効化すれば自動で起動するようになる。

$ sudo systemctl enable ruboty # 最初は無効化されているので有効化する
$ sudo systemctl start ruboty # 初回だけ手動でスタート

参考:Systemdを使ってさくっと自作コマンドをサービス化してみる - Qiita

最後に

ここまでやって遠くにあるものをSlackから写真撮影して取得できるようになりました。個人的にはこれまで立ち上がって作業してたのが不要になったのが便利でした。そして24年前のケンブリッジ大学のコーヒーマシンと同じようなことができたことが小さな小さな人生の目標を一つ達成したようで幸せな気持ちになりました。

明日は@yoshokuの「Ethereumのローカルネットワーク上で独自コインを送金する」という話です。Misoca Advent Calendarで公開されますのでお楽しみに。