DiscordのbotをPythonで作成してRaspberry Pi上で動かす

動かすまでの作業記録。

# Raspberry Pi側の準備

## バージョンとか

久しぶりの起動だったので、最新版のRaspbianを入れ直した。

```bash
pi@raspberrypi:~ $ lsb_release -a
No LSB modules are available.
Distributor ID: Raspbian
Description:    Raspbian GNU/Linux 9.4 (stretch)
Release:        9.4
Codename:       stretch
```

## Pythonとか

discord.pyが必要なので入れておく(cf. [Rapptz/discord.py: An API wrapper for Discord written in Python.](https://github.com/Rapptz/discord.py))。

```bash
pip3 install discord.py
```

あとnumpyを使った関係で以下もインストールした。これはBotを作るだけなら必須ではない。

```bash
sudo apt-get install libffi-dev
```

## SSH

設定 > Raspberry Piの設定 > インターフェイス と辿って、SSH:を**有効**にしておく。再起動が必要だったかもしれない。

# Discord側の準備

## Botを登録

[Discord - My Apps](https://discordapp.com/developers/applications/me)からボットを作成。

- New Appでアプリ追加。
- 作成したアプリの設定に入って下部のBotからCreate a Bot User。
- 上の方に戻ってGenerate OAuth2 URLへ。
- SCOPESがbotだけの状態で表示されているURLへアクセス。
- Botを登録したいサーバーを追加。

# エディタの準備

Atomを使う(使わずに直接Raspberry Pi上で作成しても良い)。以下のパッケージをインストールしておく。

- ftp-remote-edit
- platformio-ide-terminal

## FTP設定

※あらかじめRaspberry Piを起動してネットワークに接続しておく。

- Package > Ftp-Remote > Edit Servers
- サーバー名、Raspberry PiのIPアドレス、ユーザー名、パスワードを設定し、Use sftp (ssh) connectionにチェック。
    - ユーザー名とパスワードは初期状態ではpiとraspberry
    - Initial Directoryはどこでもいいが、例えば`/home/pi`にしておく。
- Package > Ftp-Remote > Toggle を選択して、Raspberry Piのディレクトリが表示されたらOK。

## SSH接続

- Alt + Shift + TでAtom内でターミナルが起動する。
- sshでRaspberry Piへ接続できたらOK。

## トークンの環境変数への登録

コード内にトークンを書きたくないので、Raspberry Piの環境変数に登録しておく。

まず、トークンを確認する。トークンは[Discord - My Apps](https://discordapp.com/developers/applications/me)下部のBot内、Token:の横のclick to revealをクリックすると分かる。

`.bash_profile`あたりに

```bash:.bash_profile
export DISCORD_TOKEN=確認したトークン
```

と言った感じで記述しておく。記述したら`source .bash_profile`とするかターミナルを再起動しておく。

# Botの作成

Raspberry Pi上に、例えばmain.pyなどの名前でファイルを作成してPythonのコードを記述し、Botの振る舞いを定義していく。

`discord.Client()`を使う方法と`discord.ext.commands.Bot()`を使う方法がある。後者だとコマンドが使えるっぽいので、今回は後者を使ってみる。

## コマンドの作成

コマンドは`[プレフィックス]関数名 引数`と言った具合のメッセージに対して実行される。例を見たほうが早いだろう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109348/90c40b41-3829-9217-616b-1c4f7a5d2e5b.png)

プレフィックスはBotのインスタンス作成時に引数として指定する。別に何でもいいし、複数指定することもできる。

```python
import discord.ext import commands
import numpy as np

BOT_PREFIX = ('?', '!')

client = commands.Bot(command_prefix=BOT_PREFIX)
```

(※numpyは以下のコマンド中で使用するためにインポートしているだけなので、特に必要という訳ではない）

コマンドに使う関数は、`@client.command()`デコレータにつづいて次のように定義する。

```python
@client.command(description="与えられた任意の数の実数の和を返します。",
                brief="数値の合計")
async def add(*num: float):
  await client.say(np.sum(num))
```

descriptionとbriefはhelp表示時に使用されるテキストで、指定せずに`@client.command()`だけでもいい。helpは自動的に作成されて、`[プレフィックス]help`でコマンドの一覧が、`[プレフィックス]help コマンド名`でコマンドのヘルプが表示される。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109348/a232d570-a4e8-b642-ca67-b4d743bd0cd9.png)

## 対話の設定

`@client.event`デコレータに続いてコードを記述するとコマンド以外の発言に対して返事をさせられる。この機能をコマンドと同時に使用するためには、関数定義中のどこかで`await client.process_commands(message)`の記述が必要なので注意する。また、Bot自身の発言に反応しないような細工もしておく必要がある。

例えば以下のようなコードを書いておくと、「こんにちは」という発言に対して自己紹介をするようになる。

```python
@client.event
async def on_message(message):
  await client.process_commands(message)

  # BOTとメッセージの送信者が同じ場合は何もしない
  if client.user == message.author:
    return

  if message.content.startswith("こんにちは"):
    m = "こんにちは! " + message.author.name + "さん!\n"
    m = m + "`!add 1 1`のように入力すると、関数が実行できます!\n"
    m = m + "`?help`で実装されている関数の一覧を表示します!"
    await client.send_message(message.channel, m)
```

![image.png](https://qiita-image-store.s3.amazonaws.com/0/109348/168e3106-b272-e520-b1c6-b66202a8a485.png)

## Botの起動

ファイルの最後に以下の記述をしておく。`import os`も必要なので注意。

```python
client.run(os.environ.get("DISCORD_TOKEN"))
```

また、以下の記述をしておくとBot起動時にターミナルにメッセージが表示される。これは必須ではない。

```python
@client.event
async def on_ready():
  print('以下のユーザー名でログインしています')
  print('ユーザー名: ' + client.user.name)
  print('ユーザーid: ' + client.user.id)
  print('------------------------------------')
```

ファイルを保存し、`python3 main.py`などとしてRaspberry Pi上でファイルを実行する。上手くログインできれば、上で設定したメッセージがターミナルに表示され、Discord上でBotがログイン状態となる。

# 作成したBot

今回作成したBotのコードは https://gist.github.com/nozma/9684af7dcb0e5e5218af81da6da59544 で公開している。

# 参考

- [DiscordのBotをRaspberry Piでポストするまでのメモ - Qiita](https://qiita.com/pinkylab/items/b5aee4a3763562e8a451)
- [Raspberry PiでのプログラミングはAtomエディタが便利 - デジカシ](https://mimimopu.com/atom_raspberry_pi_programing/)