初心者がRaspberry Pi4 Bを購入後してSlackbotでカメラ撮影するまで

# 0. はじめに
大学院の学生企画でラズパイを触る機会があり、結構面白いことがやれると判明。大学内で使えるslackbotを構築したく、ラズパイを購入しました。やりたかったことは、ラズパイのカメラモジュールを使って、slack上で写真撮影してくれるbotづくり。実験室の機器や生体試料をたまに観察したいときに使う予定です。

成果物はこんな感じ。特定のメッセージに反応して、撮影→slackへの投稿まで全部やってくれる。

|![名称未設定 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/269013/febe139f-7d5b-0d81-6fc1-f4bf5e541201.png)
|:-:|

正直何番煎じだよっていう感じなので、該当の記事はありました。しかし多くの記事が古く、様々な方法が混在しているので最新のやり方を収集するのに苦労しました。備忘録として、そして何より「これから似たようなことやるよ！」っていう人に対して少しでも役に立たせられるよう、記事にします。

購入したラズパイは[Raspberry Pi4 B 4GB](https://www.amazon.co.jp/【国内正規代理店品】Raspberry-Pi4-ModelB-ラズベリーパイ4-技適対応品/dp/B081YD3VL5?th=1)。[カメラモジュール](https://onl.bz/u2XUTcN)も購入。
他にもモニター、マウス、キーボード、microSDカード、microHDMIケーブルが必要。ケーブル以外は基本あると思います。

余談ですが、**大学生協にラズパイの公式ケースが売られていました......** 今まで気にも留めてなかったので、これには正直びっくり。

# 1. OSの書き込み

楽勝。NOOBSとかあるみたいですけどRaspberry Pi Imagerが今スタンダードらしい。
1. ラズパイ用のmicroSDカードとOS書き込み用のPCを用意する。
2. [Raspberry Pi OSのホームページ](https://www.raspberrypi.com/software/)からRaspberry Pi Imagerをインストール
3. Raspberry Pi Imagerを起動したらmicroSDカードにOSを焼く。
デフォルトは32bit版だがなんとなーく64bit版を入れてしまった。**後悔することに。**　普通に32bit版で良い。
1. microSDをラズパイに挿して起動。

# 2. ネットワーク設定
地味にハマリポイントがあるので注意。ただし設定自体は楽でした。GUIベースでやってもいいですが、ステルスssidだとCLIベースで設定しないといけません。
ここでは大学の無線LANをありがたく使わせていただくことにしました。この無線LANは**IEEE802.1X認証**の必要なネットワークで、ブラウザ認証が要らない接続方法。Winやmacは比較的容易に接続可能でしたが、**Linux（というかラズパイ？）だとかなり面倒**でした。

1. LX Terminal を起動 (Alt+Ctrl+T)
2. ```sudo iwlist wlan0 scan``` コマンドを打ち、ネットワークを探す。
3. 使用したいネットワークを見つけ、ESSIDを控えておく。
4. ```sudo nano /etc/wpa_supplicant/wpa_supplicant.conf``` コマンドで.confファイルを編集。
5. 下記を追加 (passwordはハッシュ化しておいたほうが良いが、ここでは割愛。)
記入したらCtrl + O　-> Ctrl + X

   ~~~/etc/wpa_supplicant/wpa_supplicant.conf
   network={
        ssid="控えておいたESSID"
        scan_ssid=1
        key_mgmt=WPA-EAP
        pairwise=CCMP
        auth_alg=OPEN
        eap=PEAP
        identity="IEEE802.1X認証に必要なID"
        password="IEEE802.1X認証に必要なpassword"
        phase1="peaplabel=0"
        phase2="auth=MSCHAPV2"
        priority=1
   }
   ~~~
 **Raspberry pi 3まではこれで良かったらしいのですが、4からはネットワークの変更によりもうひと手間必要。前述したハマリポイント**
   ```sudo nano /etc/dhcpcd.conf```コマンドを入力し、下記を追加。```sudo reboot```で再起動。接続されているかを確認。

   ~~~/etc/dhcpcd.conf
   interface wlan0
   env ifwireless=1
   env wpa_supplicant_driver=wext,nl80211
   ~~~

## 参考記事
[ラズパイを大学の無線LANに接続する](https://qiita.com/nishiwakki/items/5889892de9d6a983b960)
[Raspberry Pi 4 セットアップまとめ](https://zenn.dev/kenken82/articles/94b5cb52b23d88)

# 3. ssh, vnc接続設定
ずっと一つのところに置いておく運用なので、いちいちmicroHDMIケーブルを挿したくない。そこで、リモート接続を可能にするべくssh（CLIによる接続）とvnc（GUIによる接続）も有効化しておきます。これで同じLAN環境にいればリモートでファイルの編集が可能になります。設定自体は**超簡単**、さすがLinux。

1. ```sudo mkdir /boot/ssh```コマンドを実行
2. 「設定」→「Raspberry Piの設定」からSSH、VNCを有効にする。
3. ```ifconfig```コマンドを叩き、ipアドレスを控える。
4. 同一のLAN環境にいるPCからラズパイにアクセスする。
sshであれば```ssh ラズパイのユーザー名（デフォルトはpi）@控えておいたipアドレス```を接続元のPCで入力し、パスワードを打てばok。vncの場合[vnc viewer](https://www.realvnc.com/en/connect/download/viewer/)を接続元のPCにインストールし、控えておいたipアドレスで接続すればいい。もし、vnc viewer上で「Cannot currently show the desktop」と表示されたら、ラズパイ上で```sudo nano /boot/config.txt```コマンドを打ち、「#hdmi_force_hotplug=1」を「hdmi_force_hotplug=1」に修正すれば見られるはずです。

## 参考記事
[Raspberry PiのSSH設定方法](https://qiita.com/tomokin966/items/bc22d09f97ebeb3955d2)
[【ラズパイ4】「Cannot currently show the desktop」エラーでデスクトップ画面が表示されない場合の対策](https://algorithm.joho.info/raspberry-pi/cannot-currently-show-the-desktop-raspberry-pi/)

# 4. 日本語入力+VScode インストール
ラズパイはデフォルトで日本語入力に対応していないので日本語入力エンジンの Mozc をインストールする。中身は「Google日本語入力」のオープンソース版なので、変換精度はなかなか優秀。
ついでにVS Codeも入れておく。

1. LX Terminal を起動 (Alt+Ctrl+T)
2. 下記を入力しEnter。再起動される。

   ~~~
   sudo apt update
   sudo apt full-upgrade
   sudo apt install fcitx-mozc -y
   sudo apt install code -y
   sudo reboot
   ~~~
3. winキーを押す or 左上のラズパイマークを押す。
4. 設定->fcitx設定と入り、入力メソッドの設定ウィンドウを出す。
5. 全体の設定タブを開き、入力メソッドのオンオフからホットキーの設定を行う。（「空」ボタンを押した後、全角半角キーを打てば良い。「zennkakuhankaku」と入力されていれば成功）

## 参考記事
[Raspberry Piに日本語で入力できる設定方法（fcitx-mozc）](https://raspida.com/install-rpi-ime)

# 5. Slackbotの構築
様々な方法があるようで面食らいました。しかし```Slack-bolt```が公式で提供されているのでそれを活用します。一回設定できれば後は関数を追記していくだけなのでかなり楽。

1. slack_botを常駐させたいworkspace上でアプリを作成する。とりあえず[Slack ソケットモードの最も簡単な始め方](https://qiita.com/seratch/items/1a460c08c3e245b56441)と[Slack API を使用してメッセージを投稿する](https://zenn.dev/kou_pg_0131/articles/slack-api-post-message)の記事に従い、諸々の設定を行った。ソケットモードを有効にする必要があったかは正直わからない。注意すべき点はFeatures > OAuth & Permissionsで```file:write```を追加しておく点。
2. pip を使っていくつかのモジュールをインストール。```pip install opencv-python slack_bolt```ラズパイのカメラモジュールを使用する予定だったので'''PiCamera'''を一度インストール。が、**64bit版のラズパイOSだとOSエラーが出て使用できない！。（た後悔ポイント）** 仕方がないのでopencvで代用。
3. 適当なディレクトリにpythonのスクリプトを書く。書き方としては```@app.message("")```でトリガーとなるメッセージを指定し、その直後に関数定義をすればいいらしい。スクリプト自体は簡単に書けました。さすがPython。

   ~~~slack_bot.py
   import logging
   import os
   from slack_sdk import WebClient
   from slack_bolt import App
   from slack_bolt.adapter.socket_mode import SocketModeHandler
   from slack_sdk.errors import SlackApiError
   import cv2
   
   BOT_TOKEN = "BOT_TOKEN"
   APP_TOKEN = "APP_TOKEN"
   
   logger = logging.getLogger(__name__)
   
   @app.message(r"写真撮って|:camera:")
   def take_photo(message, say):
       say(f"<@{message['user']}> さん、撮影を開始します。")
       cap = cv2.VideoCapture(0) #0 or -1
       if cap.isOpened():
           ret, img = cap.read()
       if ret:
           cv2.imwrite('temp.jpg', img)
           cv2.destroyAllWindows()
       say(f"撮影完了です！")
       try:
           result = app.client.files_upload(
           channels="常駐させたいチャンネル名",
           initial_comment="撮影結果です :grin:",
           file="temp.jpg"
           )
           # Log the result
           logger.info(result)
       except SlackApiError as e:
           logger.error("Error uploading file: {}".format(e))
       os.remove("temp.jpg")
   ~~~

4. 走らせてみる。成果物と同じように、メッセージに反応して写真を撮ってくれれば成功。

##  参考記事
[Slack ソケットモードの最も簡単な始め方](https://qiita.com/seratch/items/1a460c08c3e245b56441)
[files.upload (API公式ホームページ)](https://api.slack.com/methods/files.upload)
[Slack Python SDK でチャンネルにファイルをアップロードしよう](https://qiita.com/seratch/items/2dd8e5676b09e8863618)

# 6. python fileの自動起動
いちいちpythonファイルを起動するのは面倒なので自動起動させる。様々な方法があるがsystemdを用いた方法が一番robust。結構ハマった。

1. LX Terminal を起動 (Alt+Ctrl+T)
1. ```cd /etc/systemd/system/```と入力
2. ```sudo nano 任意のサービス名.service```と入力。**サービス名は英語でわかりやすいものにする。**
3. 下記内容を入力し、保存

   ~~~/etc/systemd/system/任意のサービス名.service
   [Unit]
   Description= launch python file # サービスの内容説明
   After=network.target # ハマリポイント。Slack_botの際はこれが必須。
   
   [Service]
   ExecStart=/usr/bin/python3 /path/to/your/python/script.py
   Restart = always # 動作がおかしくなるようなら noに変える。
   [Install]
   WantedBy=default.target
   ~~~

5. ```sudo systemctl daemon-reload```でsystemdを再読み込み
5. ```sudo systemctl start 作成したサービス名```でサービスを起動
6. ```sudo systemctl status サービス名```でRunningの表示があるかを確認。ない場合は、python fileにバグが有るかサービス内の記述に間違いがないか(指定したスクリプトのpathなど)を確認
7. ```sudo systemctl enable サービス名```で自動起動をonにする
8. ```sudo reboot```。再起動後に```sudo systemctl status サービス名```でRunningの表示があるかを確認。

### 注意点
サービスで指定されているpythonファイルを修正した場合、修正後に一度```sudo systemctl stop 作成したサービス名```を行いサービスを停止させた後に5. 以降の手順をもう一度行うことを推奨。

### 参考記事
[systemctl daemon-reload って何](https://qiita.com/taro-hida/items/ec187c0fae893177e575)
[半年前の自分に教えたい systemd のハマりどころ](https://speakerdeck.com/arosh/ban-nian-qian-falsezi-fen-nijiao-etai-systemd-falsehamaridokoro?slide=4)

# 7. 最後に
以上のステップを踏めば、電源を入れるだけで指定のpythonファイルが走りますし、外部からssh or vnc接続できるのでpythonの編集や電源のオンオフ、再起動もできます。実質的に無線LANと電源が届く限り、カメラ撮影が可能になるので、研究にかなり使えるポテンシャルがありそう。あとはこのシステムを属人化させないためにも、ちゃんと後輩に引き継がさねば......。