Raspberry PiとDiscordを連携して画像を送る

# １．はじめに
　ラズパイで撮影した写真をスマホのアプリDiscordへ送信する方法を紹介します。Discordは、Lineのようなメッセージ機能を持ち、ボイスチャットにも強みがある無料で利用できるコミュニケーションツールです。モバイルからPCまで、幅広いプラットフォームで利用できます[1]。そのため、ラズパイのカメラで撮影した画像をすぐに Discord に送信することで、遠隔地からの監視やチームメンバーとの情報共有をスムーズに行うことができます。
　画像を Discord に送信する方法として、DiscordのWebhook(ウェブフック)を活用することで自動化が可能になります。Webhook とは、特定のイベントが発生したときに外部サービスへ通知を送る仕組みで、ここでは撮影した画像をリアルタイムで Discord に投稿するための「橋渡し」の役割を果たします。
　なお、Discordの利用には、アカウントの登録が必要となります。以降、DiscordをRaspberry Pi（ラズパイ）とスマホで使用して連携の方法と実例を紹介します。
 
![防犯カメラシステム.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/9e45f54b-4cfc-40e2-b254-d5061623147e.png)
#### 表.　使用したもの
 |項　目|内　容|
 |---|---|
 |ラズパイ|Raspberry Pi 5 4GB|
 |OS|Bookworm(64bit) Desktop release 2024-11-19|
 |Piカメラ|Camera Module 3|
 |チャットアプリ|Discord|
 |GPIO制御ライブラリ|lgpio |
 |電子部品|PIR(秋月電子通商106835)、ブレッドボード、etc|
 # ２．Discordでサーバーの作成とWebhook URLの取得
　ラズパイのWebブラウザを使用してDiscordにログインします。この際、日本語入力できるFireFoxを使用することをお勧めします。
 ### 2.1. サーバーの作成
　ログイン後、画面左側に表示されている「サーバーを追加」アイコンをクリックし、新しいサーバーを作成します。Discordのサーバーとは、Lineの「トーク」のような場を意味し、テキストチャンネルとボイスチャンネルが含まれます。新しサーバーを作成した後、そのサーバーのWebhookのURLを取得します。
![サーバーを追加.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/0bfe7df6-ffba-43cc-a3bf-d261d0488b6f.png)

 「サーバーの作成」のダイアログが表示されます。「オリジナルの作成」をクリックします。
 ![サーバーの作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/66cddd45-8388-42f4-8d05-11ccc509dffa.png)

 　サーバーの利用目的を尋ねられたら、「自分と友人のため」をクリックします。
 ![あなたのサーバー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/41f06604-b965-4793-bcdc-8a284d99cd3c.png)

　任意のサーバー名を入力してください。例として「MyServer」と名付けます。次に、「新規作成」をクリックします。この操作により、「MyServer」という名前のサーバーが画面左側に登録されます。
 ![サーバーをカスタマイズ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/a34d9d70-9766-40f5-bf2c-4480c4beec6b.png)

### 2.2. Webhook URLの取得
　MyServer名の右横にある下向き印をクリックして、メニューを表示させまます。
 ![下▽.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/68cea884-0b17-4ade-8e17-cff427181a5d.png)

　メニューから「サーバー設定」をクリックして、サーバープロフィールのダイアログを表示させます。
 ![サーバー設定.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/3376df72-143b-4087-a4f9-edc223851e85.png)

　アプリの「連携サービス」をクリックします。
![連携サービス.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/39f369d3-c753-4071-a624-06591d175b91.png)

　「ウェブフックを作成」をクリックします。
 ![ウェブフックを作成.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/86f4e4d3-97d7-4bea-b4d6-07da9669ab76.png)

　「Spidey Bot」をクリックします。
![Spidey Bot.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/08af8b1e-56b8-4ae4-a6b7-71e41932a0d7.png)

　「ウェブフックURLをコピー」をクリックします。クリップボードにコピーされます。後で、ラズパイのソースコードで使用します。

![ウェブフックURL.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/2a704f15-5565-4f07-bf8a-e7a617b9ebda.png)

### 2.3. コマンドを使った画像のテスト送信

　取得したWebhookのURLとシェルコマンドを使用して、Discordに画像を送信する手順について説明します。今回の例では、送信する画像ファイルは「/home/my-pi/MyApp2/test.jpg」とします。
　最初に、画像を送信するためのツールとして「curl（Client for URL）」を使用します。このツールをインストールする手順は以下の通りです。`curl` は、URLを介してデータを転送するライブラリおよびコマンドの一つであり、Webhookを使った自動化に便利です。
　最初にシステムを最新の状態に更新し、`curl` ライブラリをインストールします。
```bash
sudo apt update && sudo apt upgrade -y
sudo apt install libcurl4-openssl-dev
```

次に、送信先のWebhook URLと送信する画像ファイルのパスを定義します。以下のコマンドを使用してください（実際には、`WEBHOOK_URL` に取得したWebhookのURLを入力してください）。
```bash
WEBHOOK_URL="https://discord.com/api/webhooks/XXXX/XXXX"
FILE_PATH="/home/my-pi/MyApp2/test.jpg"
```
最後に、画像をDiscordに送信するために以下のコマンドを実行します。
```bash
curl -X POST -F "file=@$FILE_PATH" "$WEBHOOK_URL"
```
これにより、指定した画像ファイルがDiscordに送信されます。なお、Webhook URLは、重要な情報なので、慎重に管理してください。

# ３．人を検知したらPiカメラで撮影する回路
　Parallax社の焦電センサモジュール（PIR：Passive Infra-Red）は、人の動きを検知するために使用します。PIRセンサは、検知時に出力信号（OUT）を「HIGH」とし、未検知時には「LOW」とする仕組みです。この信号をRaspberry PiのGPIO16ピンに接続することで、動きをトリガーとしてPiカメラで撮影を行う回路を構築できます[3]。PIRセンサは、検知時には内蔵LEDが赤く点灯するため、動作状態を視覚的に確認することが可能です。回路を試作するにはブレッドボードを用いることがもできすが、労力と時間がかかります。なお、写真に示しているラズパイ学習ボードは、Raspbrrry Pi 4BやPi 5に対応しおり、LED、スイッチ、ADCなどを実装することできます。この学習ボードはラズパイを利用した組込み学習用途に製作されました。このプリント基板のカバーデータはフリーでダウンロードできます[4]。

表．PIRの動作
|人の動き  |	出力信号|
 |---|---|
|検知	 | HIGH  |
|未検知	 |LOW|

![PIR+人.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/eac43310-aff5-4d0a-a4d1-e7cffe4becdc.png)

![図4-1 全体像 IMG_2211_Background Removal.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/6b3be9c5-884e-4b8d-a39a-41ec33b22295.jpeg)

![学習ボード.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/631966/2bc9152b-b65c-4a3e-9ea2-1c090a6f006b.jpeg)

# ４．サンプルソースコード
### ４.1.　ソースコードの作成
　本稿では、ソースコード名を「9-CamDis01.c」とし、「/home/my-pi/MyApp2」のフォルダ内に保存しました。フォルダのパスはソースコードで指定しています。そのため、フォルダ名やパスを変更する場合は、ソースコード内の該当箇所も併せて修正してください。なお、コードの可読性のため各関数のエラー処理は割愛しています。

```C: 9-CamDis01.c
#include <stdio.h>
#include <stdlib.h>     //system,EXIT_SUCCESS
#include <lgpio.h>      //lgGpiochipOpen,lgGpioRead,etc
#include <curl/curl.h>  //curl_mime,etc

#define PI5     4       // /dev/gpiochip4
#define PI4B    0       // /dev/gpiochip0
#define PIR     16      //GPIO16をPIRと定義

#define WEBHOOK_URL　 "https://discord.com/api/webhooks/XXXX/XXXX"
#define INTVL    5      //撮影間隔(秒)

int main(void){
    int hnd;
    hnd = lgGpiochipOpen(PI5);          //またはPI4B
    lgGpioClaimInput(hnd,LG_SET_PULL_DOWN,PIR);    //プルダウン抵抗を有効

    CURL *curl;             //libcurlのHTTPリクエスト用のハンドル
    curl_mime *mime;        //HTTP POSTでMINEデータを構築するための構造体
    curl_mimepart *part;    //MIMEデータ内のパート（部分）を表す構造体

    while(1){
        if(lgGpioRead(hnd, PIR)==LG_HIGH){        //人の動きを検知したら撮影する
            system("rpicam-still -t 300 --width 640 --height 480 -o /home/my-pi/MyApp2/test.jpg");
            // 写真ファイルをバックアップとして日時付きのファイル名で保存
            system("sudo cp /home/my-pi/MyApp2/test.jpg   /home/my-pi/MyApp2/$(date +'%Y%m%d-%H%M%S').jpg");
            curl = curl_easy_init();     //libcurlの初期化

            if (curl) {    //初期化に成功した場合
                mime = curl_mime_init(curl);        //MIMEデータの初期化
                //テキストメッセージ部分を設定
                part = curl_mime_addpart(mime);
                curl_mime_name(part, "content");
                curl_mime_data(part, "画像を送信します", CURL_ZERO_TERMINATED);
                //画像ファイル部分を設定
                part = curl_mime_addpart(mime);
                curl_mime_name(part, "file");
                curl_mime_filedata(part, "/home/my-pi/MyApp2/test.jpg");

                curl_easy_setopt(curl, CURLOPT_URL, WEBHOOK_URL);   //Webhook URL設定
                curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);     //MIMEデータ設定
                curl_easy_perform(curl);    //POSTリクエスト送信

                curl_mime_free(mime);       //リソース解放
                curl_easy_cleanup(curl);
            }
            lguSleep(INTVL);    //撮影間隔(秒)
        }
        lguSleep(0.001);        //CPU使用率の抑制のため 1ms
    }
    lgGpiochipClose(hnd);
    return EXIT_SUCCESS;
}
```
4.2 プログラムのビルドして実行する
以下の手順で、人感センサーに反応して写真を撮影し、Discordに送信するプログラムを構築・実行できます。スマートフォンのDiscordで写真を確認できます。

 **ディレクトリの移動**  
   プログラムの作業ディレクトリに移動します：
   ```bash
   cd /home/my-pi/MyApp2
   ```

**プログラムのコンパイル**  
   必要なライブラリをリンクして、ソースコードをビルドします：
   ```bash
   gcc -Wall -o 9-CamDis01 9-CamDis01.c -llgpio -g -O0 -lcurl
   ```

**プログラムの実行**  
   プログラムを実行します：
   ```bash
   ./9-CamDis01
   ```
以上の手順を実行することで、センサーの動作に応じて自動的に写真が撮影され、送信されます。サンプルでは5秒ごとに撮影しますが、INTVLの値で変更できます。

# ５．まとめ
　ラズパイとDiscordの組み合わせにより、リアルタイム通知、メンバー共有、監視システムの構築が可能です。このシステムは、IoTデバイスからの情報収集、自動化されたアラート送信、さらにはセキュリティ用途など、幅広い用途に応用できます。
 　なお、サンプルコードにはWebhook URLが含まれていますが、セキュリティ面での配慮が重要です。Webhook URLは、別のファイルや環境変数を使用して管理することを推奨します。この方法により、コード内に直接記述せず、安全性を確保しながら効率的に運用することができます。
# 参考文献
[1] Discord, https://discord.com/[2] curl, https://curl.se/
[3] 菊池達也,"【改訂新版】C言語ではじめるRaspberry Pi徹底入門,"技術評論社,pp.97-101(2025 Jan.)https://gihyo.jp/book/2025/978-4-297-14647-4
[4] 【改訂新版】C言語ではじめるRaspberry Pi 徹底入門, 著者のサポートページ, https://raspi-gh2.blogspot.com/
[5] かわいいフリー素材集 いらすとや,https://www.irasutoya.com/