Arduino を使わずに Bluetooth 経由で Nintendo Switch の操作を自動化する【ポケモン自動化】【v13.0.0 まで対応】

# はじめに

Arduino（マイコン）を使わずに **Bluetooth 経由で Nintendo Switch の自動操作** ができるようになりました。
自動化には、[joycontrol](https://github.com/mart1nro/joycontrol) とその拡張用のプラグインローダー（[joycontrol-pluginloader](https://github.com/Almtr/joycontrol-pluginloader)）を使用しています。

Bluetooth 経由で制御するので、これまで面倒だった hex ファイルの書換え作業やシリアル変換アダプタの用意などが必要なくなりました。Arduino を別途購入する必要もないので、PCを持っていて Bluetooth アダプタがついている人は、ぜひ試してみてください。

本記事では、特に「[自動化のための環境構築](#自動化のための環境構築)」と「[プラグインの作成方法](#プラグインの作成方法)」について紹介します。

## Nintendo Switch v14.0.0 以降のバージョンと NXBT について

Nintendo Switch v14.0.0 頃から joycontrol の動作がかなり不安定になりました。joycontrol のメンテナンスもあまり行われていない状態ですので、joycontrol の使用は推奨いたしません。

joycontrol の代わりに NXBT という別のプロジェクトがありますので、こちらのご使用をおすすめいたします。NXBT は、現時点（2022年12月05日）で最新版の Nintendo Switch v15.0.1 でも動作確認が取れています。

https://github.com/Brikwerk/nxbt

## Nintendo Switch v12.0.0 について

2021年4月6日に配信された Nintendo Switch v12.0.0 で Bluetooth 関連のアップデートがありました。
このアップデートに伴い、本家の joycontrol では、ペアリングに失敗してしまうという現象が発生していました。

5月中旬頃に、この問題を修正した joycontrol が公開され、ちゃんと動作するようになっています。
本家の方にも Pull request が出ていましたが、まだマージされていないようです。

[GitHub - Poohl/joycontrol](https://github.com/Poohl/joycontrol)

2021年9月15日、現時点で最新版の Nintendo Switch v13.0.0 でも動作確認が取れています。
本記事の「[2. joycontrol のインストール](#2-joycontrol-のインストール)」の手順が変わっていますので、ご確認ください。

- 参考
  - https://github.com/mart1nro/joycontrol/issues/104
  - https://github.com/Brikwerk/nxbt/issues/18#issuecomment-817268531
  - https://github.com/mart1nro/joycontrol/pull/110
  - https://github.com/Poohl/joycontrol

## Nintendo Switch の自動化でできること

デモンストレーションとして、ポケモン剣盾の全自動タマゴ孵化を作成しました。
自由に拡張できるようにしたので、ポケモンだけでなく他のゲームにも簡単に応用可能です。

[YouTube -【ポケモン剣盾】全自動タマゴ孵化【Bluetooth/マイコンなし】](https://www.youtube.com/watch?v=JlspXe20-Dc)
[![【ポケモン剣盾】全自動タマゴ孵化【Bluetooth/マイコンなし】](https://img.youtube.com/vi/JlspXe20-Dc/0.jpg)](https://www.youtube.com/watch?v=JlspXe20-Dc)

## 注意事項

本記事の内容は、Nintendo Switch の本体やソフトウェア等を改造するものではありませんが、
[Nintendo Switch利用規約](https://www.nintendo.co.jp/support/switch/eula/usage_policy.html) の第1条第5項に該当する可能性がありますので、ご利用は自己責任でお願いします。

> （5）本ゲーム機本体、周辺機器、本ソフトウェア等を不正に改造しないこと、および任天堂の許諾を受けていない本ゲーム機の周辺機器およびソフトウェア等を使用しないこと

# joycontrol について

joycontrol は、Bluetooth 経由で Nintendo Switch のコントローラーをエミュレートできます。
Joy-Con（L/R）や Nintendo Switch Proコントローラーに対応しており、コマンドラインからボタンやスティックの入力が可能です。また、Amiibo バックアップファイルの読込みもできるそうです。
海外のフォーラムでは、5月頃から話題になっていました。

[GitHub - mart1nro/joycontrol](https://github.com/mart1nro/joycontrol)

## 動作検証

以下の環境で動作することを確認しました。

1. Ubuntu Desktop 20.04 LTS
2. Raspberry Pi 3 Model B（Raspberry Pi OS (32-bit) Lite Minimal image based on Debian Buster）
3. <font color="Red">**Windows 10 Pro Version 1909（VirtualBox 6.1.12 + Ubuntu Desktop 20.04 LTS）**</font> **← 今回紹介する環境**
4. （非推奨）~~Ubuntu Desktop 19.10~~
5. （非推奨）~~Windows 10 Pro Version 1909（VirtualBox 6.1.12 + Ubuntu Desktop 19.10）~~

※1 Windows Subsystem for Linux（WSL）では動作しませんでした。
※2 Ubuntu 19.10 は、動作確認が取れましたが、既にサポートが切れているので非推奨です。

# 自動化のための環境構築

今回は、Windows と VirtualBox を使用した環境構築方法について紹介します。
なお、構築を単純化するため、Ubuntu の Live Boot で導入します。
永続化させたい場合は、OSをインストールしてください。

既に Linux 環境がある場合は、「[2. joycontrol のインストール](#2-joycontrol-のインストール)」から参照してください。

## 必要なもの

- ハードウェア
  - Nintendo Switch（システムバージョン 11.0.1 以前）
  - PC
  - Bluetooth アダプタ（内蔵型、USBドングルどちらでも可）  
    ※ 一部の Bluetooth アダプタは、動作しないことがあるそうです。  
    （[GitHub - mart1nro/joycontrol](https://github.com/mart1nro/joycontrol) の Issues より）

- ソフトウェア
  - VirtualBox 6.1（Windows10上で動作させる場合のみ）
  - Ubuntu 20.04 LTS（Debian系のディストリビューションであれば動作すると思います）
  - Python3.7
  - [GitHub - mart1nro/joycontrol](https://github.com/mart1nro/joycontrol)
  - [GitHub - Almtr/joycontrol-pluginloader](https://github.com/Almtr/joycontrol-pluginloader)


## 1. Linux 環境の構築

### 1-1. VirtualBox のインストール

以下のリンクから、VirtualBox と Extension Pack をダウンロードし、順にインストールしてください。
   https://www.virtualbox.org/wiki/Downloads
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/80f33e2c-50ad-22d7-af3e-2d6fb52de4d2.png)

### 1-2. Ubuntu のダウンロード

以下のリンクから、Ubuntu 20.04 LTS の ISO イメージをダウンロードしてください。
https://www.ubuntulinux.jp/products/JA-Localized/download
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/3c97f48e-b076-744d-b00b-0292c041d519.png)

### 1-3. 仮想マシンの作成

1. VirtualBox を開き、「新規」を押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/aa72f533-c57e-9208-1c0d-f5b2eecfe4bb.png)

1. 適当な名前を付け、「Ubuntu（64-bit）」を選択して、「次へ」を押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/93874b67-f50b-b785-5b61-6efca857ea07.png)
※ Ubuntu（64-bit）の項目が出ない場合、仮想化支援機能（Intel VT/AMD-V）が有効になっていない可能性があります。UEFI/BIOS を起動して仮想化支援機能を有効にしてください。マザーボードによって設定方法が異なるので、ここでは説明を割愛します。

1. メモリサイズは、4096MB以上に設定して、「次へ」を押してください。
   Ubuntu Desktop 20.04 LTS の推奨メモリサイズは、4096MB以上です。サイズが小さいと、フリーズする可能性があります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/d7b47d81-1b60-2f92-89a7-2d16596b4c23.png)

1. 今回は、OSをインストールせずに使うので、「仮想ハードディスクを追加しない」を選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/71fa2a05-ed40-55f9-6d08-d38784740d51.png)

1. 警告が出ますが、気にせず「続ける」「作成」を押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/217ef7b7-9b75-4ff7-d691-581050b58e95.png)

### 1-4. Ubuntu の起動設定

1. 作成した仮想マシンを選択し、「設定」を押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/c647dabd-604d-047e-0a43-bfc16cc84fce.png)

1. 赤枠を矢印の通りにクリックし、「[1-2. Ubuntu のダウンロード](#1-2-ubuntu-のダウンロード)」でダウンロードした ISOイメージ（ubuntu-ja-20.04-desktop-amd64.iso）を指定してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/ba208081-bdf1-69ea-d22e-2157d8f6571a.png)

1. 指定できたら、「OK」を押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/7d568a11-c64d-d9f9-bb5d-c449e5ba4d7b.png)

### 1-5. Bluetooth デバイスの接続設定

1. 作成した仮想マシンを選択し、「設定」を押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/44142b7d-3b4d-6ca9-48bc-756e570e66c8.png)

1. Bluetooth デバイスを指定してください。使用している環境によって名前が異なります。
   私の環境では、以下のような表記になっていました。
   - Intel Corp. [0001]（内蔵型の Bluetooth デバイス）
   - Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)[8891]  
     （Bluetooth USB アダプタ: [BUFFALO BSBT4D200BK](https://www.buffalo.jp/product/detail/bsbt4d200bk.html)）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/80938be1-faca-3158-fc25-1f7bfd8d07c7.png)

1. デバイスが追加されたら、「OK」を押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/583c121d-08f2-b596-6a54-1a5aa764d153.png)

### 1-6. 仮想マシンの起動

1. 作成した仮想マシンを選択し、「起動」を押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/4b73405c-6010-bd47-097f-fe66b8f0a44a.png)

1. 起動後しばらくしたら、以下のような画面になります。
   今回は、OSをインストールせずに起動させるので、「Ubuntu を試す」を押してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/7067a848-356d-038d-f9ec-700ab8df4e5f.png)

1. Ubuntu のデスクトップ画面が表示されたら、Bluetooth が「オン」になっているかを確認してください。
   「オン」になっていない場合は、「[Bluetooth がオンにならない場合](#bluetooth-がオンにならない場合)」をご確認ください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/f0cbcff7-2613-0cf6-351f-16f427f68c04.png)

### Bluetooth がオンにならない場合

一度、仮想マシンの電源をオフにしてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/ace23097-4081-e83c-da0a-9b313c254869.png)

Windows の Bluetooth 機能を無効にすると、仮想マシン側で認識される場合があります。
以下の**いずれか**をお試しください。以下の作業が完了したら、「[1-6. 仮想マシンの起動](#1-6-仮想マシンの起動)」を行ってください。

- Bluetooth デバイスを無効にする。
  1. 「デバイスマネージャー」を起動してください。
  2. Bluetooth デバイスを右クリックして「デバイスを無効にする」を押してください。  
  ※1 デバイス名は、環境によって異なります。  
  ※2 私の環境では、この方法で Bluetooth USB アダプタ（[BUFFALO BSBT4D200BK](https://www.buffalo.jp/product/detail/bsbt4d200bk.html)）が認識されました。  
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/2b49dfe7-53fa-0cc8-1a4c-2cbb4eb3d047.png)


- 3つの Bluetooth 関連のサービスを停止させる。
  1. 「サービス」を起動してください。
  2. 各サービスを右クリックし、「停止」を押してください。  
  ※1 仮想マシンの再起動を行うと、自動的にサービスが再起動される場合があります。  
  ※2 私の環境では、この方法で 内蔵型の Bluetooth デバイスが認識されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/3456a884-7c1b-353e-7a62-6f95908ee957.png)

## 2. joycontrol のインストール

ここからは、Terminal で作業を行います。Ubuntu の場合、Ctrl-Alt-T で Terminal を開くことができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/30df080d-7442-eb50-c179-6badb2081f95.png)


### 自動インストール

以下のコマンドを実行すると、joycontrol のインストール作業をすべて自動で行ってくれます。
Ubuntu の仮想マシンを起動してすぐには、コピペが使えません。入力が面倒な人は、これを使ってください。

```sh
wget -O - https://bit.ly/3aqvkpu | sh
```

### （オプション）手動インストール

1. 依存関係のあるパッケージなどをインストールする。

    ```sh
    sudo apt update
    sudo apt install git python3-pip python3-dbus libhidapi-hidraw0 libbluetooth-dev bluez -y
    ```

1. Bluetooth の関連の設定（ペアリング時に必要な設定）

    SDP を無効化させる。

    ```sh
    sudo sed -i -e 's/bluetoothd$/bluetoothd -C -P sap,input,avrcp/' /lib/systemd/system/bluetooth.service
    ```

    bluetooth-deamon を再起動して、設定を反映させる。

    ```sh
    sudo systemctl daemon-reload
    sudo systemctl restart bluetooth.service
    ```

1. joycontrol をインストールする。

    ```sh
    git clone https://github.com/Poohl/joycontrol.git -b amiibo_edits ~/joycontrol
    sudo pip3 install aioconsole hid==1.0.0 crc8
    sudo pip3 install joycontrol/
    ```

1. joycontrol-pluginloader をインストールする。

    ```sh
    git clone --recursive https://github.com/Almtr/joycontrol-pluginloader.git
    sudo pip3 install joycontrol-pluginloader/
    ```

## 3. コントローラーのペアリング

1. Nintendo Switch を起動し、以下の画面を開いてください。
   「HOME」→「コントローラー」→「持ちかた/順番を変える」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/dfbf5256-b4d1-cbea-6359-89d985ec5e2e.png)

1. ディレクトリを移動する。

    ```sh
    cd joycontrol-pluginloader/
    ```

1. 以下のコマンドを実行してください。
   
    ```sh
    sudo joycontrol-pluginloader plugins/tests/PairingController.py
    ```
       
    ペアリングに成功すると、以下のような実行ログが表示されます。ペアリングがうまくいかない場合は、「[ペアリングできない場合](#ペアリングできない場合)」をご確認ください。

    ```terminal
    [17:03:13] joycontrol.server create_hid_server::58 WARNING - [Errno 98] Address already in use
    [17:03:13] joycontrol.server create_hid_server::60 WARNING - Fallback: Restarting bluetooth due to incompatibilities with the bluez "input" plugin. Disable the plugin to avoid issues. See https://github.com/mart1nro/joycontrol/issues/8.
    [17:03:13] joycontrol.server create_hid_server::65 INFO - Restarting bluetooth service...
    [17:03:14] joycontrol.device set_name::69 INFO - setting device name to Pro Controller...
    [17:03:14] joycontrol.device set_class::61 INFO - setting device class to 0x002508...
    [17:03:14] joycontrol.server create_hid_server::84 INFO - Advertising the Bluetooth SDP record...
    [17:03:14] joycontrol.server create_hid_server::94 INFO - Waiting for Switch to connect... Please open the "Change Grip/Order" menu.
    [17:03:16] joycontrol.server create_hid_server::98 INFO - Accepted connection at psm 17 from ('01:23:45:67:89:AB', 17)
    [17:03:16] joycontrol.server create_hid_server::100 INFO - Accepted connection at psm 19 from ('01:23:45:67:89:AB', 19)
    [17:03:18] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.REQUEST_DEVICE_INFO
    [17:03:18] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.SET_SHIPMENT_STATE
    [17:03:18] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.SPI_FLASH_READ
    [17:03:18] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.SPI_FLASH_READ
    [17:03:18] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.SET_INPUT_REPORT_MODE
    
    <snip>
    
    [17:04:04] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.SET_NFC_IR_MCU_CONFIG
    [17:04:04] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.SET_PLAYER_LIGHTS
    [17:04:04] JoycontrolPlugin.loader load_plugin::9 INFO - Loading: plugins/tests/PairingController.py
    [17:04:05] plugins/tests/PairingController.py run::11 INFO - Pairing completed.
    [17:04:06] JoycontrolPlugin.loader start::55 INFO - Stopping communication...
    ```

「Pairing completed. 」と表示され、Nintendo Switch が以下の画面に遷移したら、ペアリング成功です。
<font color="Silver">（ペアリング成功後、Aボタンを自動入力して、この画面に遷移させ、一度切断するように実装しています。）</font>
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/f0bef917-57ac-2d29-13cb-70df33fe90b8.png)

### ペアリングできない場合

まずは、Bluetooth がオンになっていることを確認してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/f0cbcff7-2613-0cf6-351f-16f427f68c04.png)

- **「Waiting for Switch to connect... Please open the "Change Grip/Order" menu.」の表示から動かない。**

     3 分程度待っても何も起きない場合は、Ctrl-C で強制終了し、再度以下のコマンドを実行してください。何度か強制終了と再実行を繰り返すと、先に進む場合があります。

    ```sh
    sudo joycontrol-pluginloader plugins/tests/PairingController.py
    ```

- **「KeyError: 'Name'」というエラーが出る。**

    ペアリング時に以下のようなエラーが出る場合があります。

    ```
    [14:56:17] joycontrol.server create_hid_server::64 WARNING - detected too many SDP-records. Switch might refuse connection.
    Traceback (most recent call last):
      File "/usr/local/bin/joycontrol-pluginloader", line 8, in <module>
        sys.exit(main())
      File "/usr/local/lib/python3.8/dist-packages/JoycontrolPlugin/loader.py", line 90, in main
        loop.run_until_complete(loader.start(args))
      File "/usr/lib/python3.8/asyncio/base_events.py", line 616, in run_until_complete
        return future.result()
      File "/usr/local/lib/python3.8/dist-packages/JoycontrolPlugin/loader.py", line 39, in start
        transport, protocol = await create_hid_server(factory, reconnect_bt_addr=args.reconnect_bt_addr,
      File "/usr/local/lib/python3.8/dist-packages/joycontrol/server.py", line 65, in create_hid_server
        b = hid.get_paired_switches()
      File "/usr/local/lib/python3.8/dist-packages/joycontrol/device.py", line 77, in get_paired_switches
        if d and d['Name'] == "Nintendo Switch":
    KeyError: 'Name
    ```

    これは bluetooth-daemon を再起動すると、解決する場合があります。
    以下のコマンドを実行して bluetooth-daemon を再起動してください。

    ```sh
    sudo systemctl restart bluetooth.service
    ```

- **bluetoothd の input plugin を無効にする**

    bluetoothd の input plugin を無効にすると、ペアリングができる場合があるそうです。
    （参考）https://github.com/Poohl/joycontrol/blob/amiibo_edits/README.md

   1. /lib/systemd/system/bluetooth.service をエディタで開く。
 
      ```sh
      sudo gedit /lib/systemd/system/bluetooth.service
      ```

   1. 「ExecStart=/usr/lib/bluetooth/bluetoothd」から始まる行を以下のように編集する。

      ```
      ExecStart=/usr/lib/bluetooth/bluetoothd -C -P input
      ```

   1. bluetooth-daemon を再起動して設定を反映させる。

      ```
      sudo systemctl daemon-reload
      sudo systemctl restart bluetooth.service
      ```

- **上記の方法のいずれかでもペアリングできない場合**

    別の Bluetooth デバイスを試してみてください。呪われた Bluetooth ハードウェアがあるそうです。
    （参考）[Cursed Bluetooth Hardware · Issue #4 · Poohl/joycontrol](https://github.com/Poohl/joycontrol/issues/4)


## 4. 動作テスト

1. Nintendo Switch の Bluetooth アダプタの MAC アドレスを確認する。
   ペアリング時の実行ログを再度確認し、以下のようなメッセージを探してください。

    > [17:03:16] joycontrol.server create_hid_server::98 INFO - Accepted connection at psm 17 from ('01:23:45:67:89:AB', 17)

    <font color="Red">**上記の例の場合、「01:23:45:67:89:AB」が Bluetooth アダプタの MAC アドレスです。今後コマンドの実行時に使用するので、覚えておいてください。**</font>
    ※ 接続する Nintendo Switch によって MAC アドレスの値は、異なります。

1. Nintendo Switch で以下の画面を開いてください。
  「HOME」→「設定」→「コントローラーとセンサー」→「入力デバイスの動作チェック」
   →「ボタンの動作チェック」
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/a13c223f-e0a4-36cc-b6a7-f58a0ea1a177.png)

1. すべてのコントローラーの接続を切断してください。
   ※ 切断できていない場合、エラーになる可能性があります。

1. 以下のコマンドを実行してください。
   
    ```sh
    sudo joycontrol-pluginloader -r 01:23:45:67:89:AB plugins/tests/TestControllerButtons.py 
    ```

    ※「01:23:45:67:89:AB」には、ご自身の Nintendo Switch の Bluetooth アダプタの MAC アドレスを指定してください。
    
    実行すると、いくつかのボタンが自動入力されます。
    ![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/180414/b2ed91fd-58db-534f-e2e7-2777f379234a.png)

# joycontrol プラグインについて

なるべく自動化の実装コストを下げるため、プラグインとして拡張できるようなツールを作成しました。
これらを使って、「[Nintendo Switch の自動化でできること](#nintendo-switch-の自動化でできること)」の全自動タマゴ孵化や「[4. 動作テスト](#4-動作テスト)」のボタン自動入力などを実現しています。

- [joycontrol-pluginloader](https://github.com/Almtr/joycontrol-pluginloader)（joycontrol 拡張用のプラグインローダー）
- [joycontrol-plugins](https://github.com/Almtr/joycontrol-plugins)（ポケモン自動化などのプラグイン）

## 同封しているプラグインと使い方

各プラグインの使い方は、[Wiki](https://github.com/Almtr/joycontrol-plugins/wiki)をご確認ください。

- サンプルプラグイン
    - サンプル（SamplePlugin）
- テスト用プラグイン
    - ペアリングテスト（ParingController）
    - コントローラーのボタン入力テスト（TestControllerButtons）
    - コントローラーのスティック入力テスト（TestControllerSticks）
- ユーティリティプラグイン
    - Aボタン連打（RepeatA）
    - 簡易マクロ（SimpleMacro）
- ポケモンソード・シールドプラグイン
    - 日付変更バグ（TimeSkipGlitch）
        - ほりだしもの自動購入（BuyBargains）
        - マックスレイドバトルのポケモン切替え（ChangeRaidPokemon）
        - きのみ自動回収（GetBerries）
        - ハネ自動回収（GetFeathers）
        - ワット自動回収（GetWatts）
        - 自動IDくじ（TryLotoID）
    - マックスレイドバトル周回（AutoRaid）
    - あまいミツとふしぎなアメの合成（CombineHoneyAndCandy）
    - マックスレイドバトル配布（DistributeRaid）
    - 自動タマゴ孵化（HatchEggs）
    - トーナメント周回（LoopBattleTower）
    - バトルタワー周回（LoopTournament）
    - ポケモン自動逃がし（ReleasePokemons）
    - 乱数調整用の日数消費（SkipDays）

今後余裕があれば、追加実装していきます。

<details><summary>（2020/08/09 追記）7つのプラグインを追加しました。</summary><div>

- 日付変更バグ（TimeSkipGlitch）
    - ほりだしもの自動購入（BuyBargains）
    - きのみ自動回収（GetBerries）
    - ハネ自動回収（GetFeathers）
    - ワット自動回収（GetWatts）
    - 自動IDくじ（TryLotoID）
- マックスレイドバトル周回（AutoRaid）
- あまいミツとふしぎなアメの合成（CombineHoneyAndCandy）

</div></details>

<details><summary>（2020/08/23 追記）[@zobio_go](https://twitter.com/zobio_go) さんに3つのプラグインを作成していただきました。</summary><div>

- 日付変更バグ（TimeSkipGlitch）
    - マックスレイドバトルのポケモン切替え（ChangeRaidPokemon）
- マックスレイドバトル配布（DistributeRaid）
- 乱数調整用の日数消費（SkipDays）

</div></details>

## プラグインの作成方法

プラグイン作成用に4つのサンプルを用意しました。
ここに書かれているサンプルの組み合わせで大体の自動化ができると思います。

### 最小構成

プラグインを作成する場合、クラス名とファイル名を一致させてください。
作成したクラスの run メソッドがエントリーポイントです。

以下のサンプルでは、プラグインがロードされた後、「Hello joycontrol Plugin!」と出力されます。

- ログ出力サンプル

    ```python:MyPlugin.py
    import logging
    from JoycontrolPlugin import JoycontrolPlugin
    
    logger = logging.getLogger(__name__)
    
    # クラス名とファイル名を一致させる
    class MyPlugin(JoycontrolPlugin):
        # run メソッドがエントリーポイント
        async def run(self):
            logger.info('Hello joycontrol Plugin!') # ログ出力
    ```

- 実行方法

    ```sh
    sudo joycontrol-pluginloader -r 01:23:45:67:89:AB MyPlugin.py
    ```
    ※「01:23:45:67:89:AB」には、ご自身の Nintendo Switch の Bluetooth アダプタの MAC アドレスを指定してください。

- 実行結果

    ```text
    [21:28:33] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.REQUEST_DEVICE_INFO
    [21:28:33] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.SET_SHIPMENT_STATE
    [21:28:33] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.SPI_FLASH_READ
    
    <snip>
    
    [21:28:36] JoycontrolPlugin.loader __load_plugin::22 INFO - Loading: MyPlugin.py
    [21:28:36] MyPlugin.py run::10 INFO - Hello joycontrol Plugin!
    [21:28:36] JoycontrolPlugin.loader start::55 INFO - Stopping communication...
    ```

### ボタンを押す

ボタンの入力用に3つのメソッド（button_push、button_press、button_release）を用意しています。
以下のサンプルでは、ボタンの入力、同時押し、順番に離す、長押しを行います。

- ボタン入力サンプル

    ```python:MyPlugin.py
    import logging
    from JoycontrolPlugin import JoycontrolPlugin
    
    logger = logging.getLogger(__name__)
    
    class MyPlugin(JoycontrolPlugin):
        async def run(self):
            await self.button_push('a') # Aボタンを押す
            await self.wait(0.3) # 0.3秒間待つ
    
            await self.button_push('a', 'b') # AとBボタンを同時に押す
            await self.wait(0.3)
    
            await self.button_press('a', 'b', 'x') # A、B、Xボタンを同時に押し続ける
            await self.wait(0.1)
    
            await self.button_release('x') # Xボタンだけ離す
            await self.wait(0.1)
    
            await self.button_release('a', 'b') # AとBボタンも離す
            await self.wait(0.1)
    
            await self.button_push('a', press_time_sec=3.0) # Aボタンを3秒間長押しする
            await self.wait(0.3)
    ```

- 実行方法

    ```sh
    sudo joycontrol-pluginloader -r 01:23:45:67:89:AB MyPlugin.py
    ```
    ※「01:23:45:67:89:AB」には、ご自身の Nintendo Switch の Bluetooth アダプタの MAC アドレスを指定してください。

- 使用できるボタン

    |ラベル  |ボタン名  |
    |---|---|
    |a|Aボタン|
    |b|Bボタン|
    |x|Xボタン|
    |y|Yボタン|
    |l|Lボタン|
    |r|Rボタン|
    |zl|ZLボタン|
    |zr|ZRボタン|
    |l_stick|Lスティックボタン|
    |r_stick|Rスティックボタン
    |minus|-ボタン|
    |plus|+ボタン|
    |up|十字ボタン（上）|
    |down|十字ボタン（下）|
    |left|十字ボタン（左）|
    |right|十字ボタン（右）|
    |capture|キャプチャーボタン|
    |home|HOMEボタン|

### スティックを傾ける

スティックの入力用に2つのメソッド（left_stick、right_stick）を用意しています。
以下のサンプルでは、「左スティックと右スティックを傾ける」、「角度を指定して傾ける」、「少しだけ傾ける」、「中央に戻す」を行います。

- スティック入力サンプル

    ```python:MyPlugin.py
    import logging
    from JoycontrolPlugin import JoycontrolPlugin
    
    logger = logging.getLogger(__name__)
    
    class MyPlugin(JoycontrolPlugin):
        async def run(self):
            await self.left_stick('up') # 左スティックを上に傾ける
            await self.wait(0.3) # 0.3秒間待つ
    
            await self.right_stick('down') # 右スティックを下に傾ける
            await self.wait(0.3)
    
            await self.left_stick(angle=45) # 左スティックを左上（45度）に傾ける
            await self.wait(0.3)
    
            half_power = self.max_stick_power / 2
            await self.left_stick('right', power=half_power) # 左スティックを半分の力で右に傾ける
            await self.wait(0.3)
    
            await self.left_stick('center') # 左スティックを中央に戻す
            await self.right_stick('center') # 右スティックを中央に戻す
            await self.wait(0.3)
    ```

- 実行方法

    ```sh
    sudo joycontrol-pluginloader -r 01:23:45:67:89:AB MyPlugin.py
    ```
    ※「01:23:45:67:89:AB」には、ご自身の Nintendo Switch の Bluetooth アダプタの MAC アドレスを指定してください。

### コマンドライン引数からオプションを指定する

``--plugin-options`` や ``-p`` を使ってオプションを指定することができます。
以下のサンプルでは、2つのオプションを受け取り、それらをログに出力します。

- オプション指定サンプル

    ```python:MyPlugin.py
    import logging
    from JoycontrolPlugin import JoycontrolPlugin, JoycontrolPluginError
    
    logger = logging.getLogger(__name__)
    
    class MyPlugin(JoycontrolPlugin):
        async def run(self):

            # エラー処理
            if self.options is None:
                raise JoycontrolPluginError('Plugin options is not set.')
    
            logger.info(self.options[0]) # 1つ目のオプション
            logger.info(self.options[1]) # 2つ目のオプション
    ```

- オプションの指定方法

    ```sh
    sudo joycontrol-pluginloader -r 01:23:45:67:89:AB MyPlugin.py --plugin-options hello abc
    ```
        
    もしくは
    
    ```sh
    sudo joycontrol-pluginloader -r 01:23:45:67:89:AB MyPlugin.py -p hello abc
    ```
    ※「01:23:45:67:89:AB」には、ご自身の Nintendo Switch の Bluetooth アダプタの MAC アドレスを指定してください。

- 実行結果

    ```text
    [21:36:00] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.REQUEST_DEVICE_INFO
    [21:36:00] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.SET_SHIPMENT_STATE
    [21:36:00] root _reply_to_sub_command::295 INFO - received output report - Sub command SubCommand.SPI_FLASH_READ
    
    <snip>
    
    [21:36:03] JoycontrolPlugin.loader __load_plugin::22 INFO - Loading: MyPlugin.py
    [21:36:03] MyPlugin.py run::8 INFO - hello
    [21:36:03] MyPlugin.py run::9 INFO - abc
    [21:36:03] JoycontrolPlugin.loader start::55 INFO - Stopping communication...
    ```

# おわりに

これまでは、Arduino を使って自動化させていましたが、joycontrol を使って Bluetooth 経由で自動化することができるようになりました。hex ファイルの書換えが必要なくなったので、かなり便利になりました。
実装コストもかなり下がったので、時間のあるときに移植していきたいと思います。

# 参考資料

- [GitHub - mart1nro/joycontrol](https://github.com/mart1nro/joycontrol)
- [Discord - Joy-ConDroid Discord](https://discord.gg/SQNEx9v) #hacking チャンネル
- [GitHub Gist - amiibo-emulation-with-linux-vm.md](https://gist.github.com/colemickens/b08d1a339f4483c6b3c08e739d6cf5d0)
- [GitHub - Poohl/joycontrol (Nintendo Switch V12 に対応した joycontrol)](https://github.com/Poohl/joycontrol)
- [Unable to connect with Switch update 12.0.0 · Issue #104 · mart1nro/joycontrol](https://github.com/mart1nro/joycontrol/issues/104)
- [Support for SwitchOS 12.0.0 · Issue #18 · Brikwerk/nxbt](https://github.com/Brikwerk/nxbt/issues/18#issuecomment-817268531)
- [V12 compatability and Amiibo-NFC support. by Poohl · Pull Request #110 · mart1nro/joycontrol](https://github.com/mart1nro/joycontrol/pull/110)
- [Cursed Bluetooth Hardware · Issue #4 · Poohl/joycontrol](https://github.com/Poohl/joycontrol/issues/4)