Raspberry Pi Picoを使ってパスコード自動入力機を作る【後編】 / Adafruit Trinkey QT2040

# はじめに

前回の続きです。
[前回の記事](https://qiita.com/koushiro/items/2587b45de2e34d4b9cd7)をまだ読まれていない方は、そちらを読んでから本稿をお読みいただけるとより楽しめます。

前回は`Raspberry Pi Pico` (以下`ラズパイピコ`)を用いて、**パスワードを自動で入力するプログラム**を製作しました。

![eacb998e-6884-4f33-bec7-31c1b0b382b4.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/7bc8af58-07cc-9144-a78c-1370e1d7835a.jpeg)

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ラズパイピコをHIDデバイス(キーボード)と認識させて、任意の文字列を打ち込むテスト <a href="https://t.co/YbUPXdT0Yr">pic.twitter.com/YbUPXdT0Yr</a></p>&mdash; Koushiro (@Koushiro_A) <a href="https://twitter.com/Koushiro_A/status/1500283436812046336?ref_src=twsrc%5Etfw">March 6, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

今回は**新たなデバイス**を使って、パスワード入力機を完成させます。

# 前回の課題点

前回明らかになった課題点が2つありました。

1つ目は**セキュリティ面が弱い**という点でした。
今回使うファームウェアの`CircuitPython`は、PCに接続した際、ストレージとして認識されますが、
**これだとソースコードが丸見えになってしまいます。**
今回はこれを解決します。
<br>

2つ目は**スタイリッシュではない**という点でした。
前回はラズパイピコを使って実装しましたが、パスワードを自動で入力するだけのデバイスとしては大きすぎました。
特に、今回使っていないGPIOピンは必要ないですし、PCと接続するためにはmicroUSBケーブルを用意しなければなりません。
これを**新たなデバイスを用意する**ことで解決します。

# 今回使うデバイス

今回使うのが、**`Adafruit Trinkey QT2040`** というデバイスです。

https://learn.adafruit.com/adafruit-trinkey-qt2040

![QT2040_1.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/8b62c41a-2087-72d9-a26c-56d7a5ac78a1.jpeg)

![QT2040_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/f04aff90-2215-5085-04d7-a8f7f663ed4b.jpeg)

このデバイスはラズパイピコの心臓部であるチップ`RP2040`と同じものを積んでおり、ラズパイピコでのプログラム等をそのまま移植することができます。

そして見ての通り、**GPIOピンが一切ありません!**
これで小型化を実現できます。

さらに!
PCB上にUSB-A端子があり、**直接USBポートに挿すことができます!**
これで、接続のためのmicroUSBケーブルも必要ありません。

これで課題点の2つ目はクリアとなります。

# CircuitPythonにおける起動手順

ここで、課題点1つ目を解決するために、CircuitPythonにおける起動手順、いわゆるブートシーケンスについて整理したいと思います。
以下のサイトを参考にさせていただきました。

http://mpu.wikidot.com/411-mp-boot

こちらのサイトより、MicroPython及びCircuitPythonのブートシーケンスを引用させていただくと、

> 1. MicroPython システム起動
> 2. boot.py 実行
> 3. REPL および USB ドライブ動作開始
> 4. main.py 実行
> 5. code.py 実行(CircuitPython のみ？)

このようになっているようです。

前回書いたプログラムは、`code.py`だったので、上の手順によると一番最後に実行されることとなります。

一方上述のブートシーケンスによると、現在課題となっているUSBドライブが動作する前に、`boot.py`というプログラムが実行されるようです。
つまり、ここで**ソースコードを見せないような処理を書けば良い**ということになります。

# boot.pyで書く処理について

上で述べたように、`boot.py`の中でストレージを無効化出来ればな～と思い、色々とリサーチしていました。
すると、Adafruit公式の以下のサイトを発見しました。

https://learn.adafruit.com/customizing-usb-devices-in-circuitpython/circuitpy-midi-serial#circuitpy-mass-storage-device-3096583-4

こちらに、以下のような記述がありました。

>The CIRCUITPY drive is normally visible on the host computer. To disable it showing up as a USB device, use code like this in boot.py:

訳すと…

>CIRCUITPYドライブは通常、ホストコンピュータ上に表示されます。USBデバイスとして表示されないようにするには、boot.pyで次のようなコードを使用します。

ということです。
そして、そのコードというのがこちらです。

```python:boot.py
import storage

storage.disable_usb_drive()
```

プログラムの意味としては、

1. `storage`ライブラリをインポート
2. USBドライブを無効化する関数を実行

といった感じです。

`storage`ライブラリについては、以下のリファレンスに詳しく書かれています。

https://docs.circuitpython.org/en/latest/shared-bindings/storage/index.html

これにより、**ストレージが無効化→すなわちソースコードが見られる心配が(ほぼ)無い**ので、課題点1つ目もクリアとなります。
(実は抜け道はありますが、それはまたの機会に…)

ということでQT2040のストレージには、

- USBドライブを無効化する`boot.py`
- メインプログラム用の`code.py`

の2つのファイルを保存することとなります。

# プログラムの修正

Adafruit Trinkey QT2040には**プログラマブルボタンが1つ**と、**NeopixelのフルカラーLED**が搭載されていますので、これを使えるように少しだけプログラムを修正します。
↓参考にAdafruit Trinkey QT2040のピンアサイン[(Adafruit公式ページより)](https://learn.adafruit.com/adafruit-trinkey-qt2040/pinouts)

![sensors_Untitled.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/7fc3ec9c-a1a6-4254-b4d9-0e0fbc405adc.jpeg)

```python:code.py
import usb_hid
from adafruit_hid.keyboard import Keyboard
from time import sleep
import board
import neopixel
import digitalio

keyboard = Keyboard(usb_hid.devices)

pixel_pin = board.NEOPIXEL
num_pixels = 1

pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False)

button = digitalio.DigitalInOut(board.BUTTON)
button.direction = digitalio.Direction.INPUT

RED = 0xFF0000
GREEN = 0x00FF00
BLUE = 0x0000FF
YELLOW = 0xFFFF00

#パスコード(例) : ABCDEfghij01234

pass_list = [4,5,6,7,8,9,10,11,12,13,39,30,31,32,33]
big_or_small = [1,1,1,1,1,0,0,0,0,0,0,0,0,0,0]

pixels[0] = YELLOW
pixels.show()
sleep(0.5)

while button.value==True:
    sleep(0.01)

pixels[0] = GREEN
pixels.show()

for i in range(len(pass_list)):
    if big_or_small[i]==1:
        keyboard.press(225)
        sleep(0.01)
    keyboard.send(pass_list[i])
    sleep(0.01)
    keyboard.release(225)

keyboard.send(40)

pixels[0] = RED
pixels.show()
sleep(10)

```

## ボタンについて

ボタンについての記述を抜粋します。

```python:code.py
import board
import digitalio

button = digitalio.DigitalInOut(board.BUTTON)
button.direction = digitalio.Direction.INPUT

while button.value==True:
    sleep(0.01)
```

ライブラリは`board`と`digitalio`の2つをインポートします。(1・2行目)

次に、`button`という変数を用意し、これがボタンのIOであると定義します。(4行目)
さらに、IOをインプットであると認識させます。(5行目)

これにより、`button.value`でボタンが押されているか(`False`)、いないか(`True`)を取得することができ、7行目のように**ボタンが押されるまで待機**といった処理が可能となります。

## NeoPixel フルカラーLEDについて

先述の通り、Adafruit Trinkey QT2040にはAdafruitのNeoPixel規格のフルカラーLEDが1個搭載されています。
↓こんな感じ

![P3220004.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/45f7013a-0a51-0046-d11a-d4c6c096ee00.jpeg)

これを制御するのが、以下のプログラムです。(上記プログラムより抜粋)

```python:code.py
import board
import neopixel

pixel_pin = board.NEOPIXEL
num_pixels = 1

pixels = neopixel.NeoPixel(pixel_pin, num_pixels, brightness=0.3, auto_write=False)

RED = 0xFF0000
GREEN = 0x00FF00
BLUE = 0x0000FF
YELLOW = 0xFFFF00

pixels[0] = YELLOW
pixels.show()
```

ライブラリは`board`と`neopixel`の2つをインポートします。(1・2行目)
なお、`neopixel`ライブラリは前回の`adafruit_hid`と同様に、ライブラリファイルをボード側に転送しておく必要があります。
やり方に関しては前回の記事の[ライブラリ導入手順]()を参考にしてください。

次に、変数`pixel_pin`を用意し、board上のNEOPIXELを指定します。(4行目)

さらに、変数`num_pixels`を用意し、LEDの数を指定します。(5行目)
今回は1つしかありませんが、数珠つなぎにして複数個操ることも可能です。

続いて新たに変数(正確にはリスト)`pixels`を用意し、`neopixel`の関数を用いて、LEDを定義します。(7行目)

ここまででLEDの設定は終わりましたが、光らせる色を簡単に指定するために、よく使う色を定義しておきます。
それぞれ、
【9行目】赤 `#FF0000`
【10行目】緑 `#00FF00`
【11行目】青 `#0000FF`
【12行目】黄 `#FFFF00`
となります。

これにより、14行目のように変数名(すなわち色の名前)を指定するだけで、光らせたい色を指定できます。
最後に15行目の`pixels.show()`という関数により、LEDは点灯を始めます。

## 色の意味

フルカラーLEDは、今回のデバイスの唯一のインジケータとなります。
プログラム中の色の意味は、

黄 `#FFFF00`　→　入力準備完了
緑 `#00FF00`　→　入力中
赤 `#FF0000`　→　入力完了・終了待機中

というようになっています。

# 実行映像

ここまでで大方のプログラムが出来上がったので、実際にテストしてみた映像を御覧いただきたいと思います。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">ラズパイピコの互換機「Adafruit Trinkey QT2040」を使ってパスコード自動入力機を作ったので、Windowsへの自動ログインをデモ<a href="https://twitter.com/hashtag/Adafruit?src=hash&amp;ref_src=twsrc%5Etfw">#Adafruit</a> <a href="https://twitter.com/hashtag/RaspberryPi?src=hash&amp;ref_src=twsrc%5Etfw">#RaspberryPi</a> <a href="https://twitter.com/hashtag/RaspberryPiPico?src=hash&amp;ref_src=twsrc%5Etfw">#RaspberryPiPico</a> <a href="https://twitter.com/hashtag/CircuitPython?src=hash&amp;ref_src=twsrc%5Etfw">#CircuitPython</a> <a href="https://t.co/ePlKkB0n0R">pic.twitter.com/ePlKkB0n0R</a></p>&mdash; Koushiro (@Koushiro_A) <a href="https://twitter.com/Koushiro_A/status/1506289793264947204?ref_src=twsrc%5Etfw">March 22, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

# 本体保護について

今回使ったAdafruit Trinkey QT2040ですが、小さくてコンパクトなのはいいものの、PCBの上に素子が載っていて、それが剥き出しという状態なのはちょっと怖いですよね。
素子が載っている面に圧力がかかると、すぐに壊れてしまいそうです。

そこで、↓こちらの画像を参考にして、基盤を保護するための部品を製作することにしました。

![sensors_QTT_sensor_connected.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/b17c87ce-98fd-19e5-ab2f-4afcab6034d0.jpeg)

## 3DPCBの取得

https://github.com/adafruit/Adafruit-Trinkey-QT2040-PCB

まず、Adafruit Trinkey QT2040の3DPCBが、Adafruit公式のGithubリポジトリにアップされているので、こちらよりダウンロードします。
ダウンロードできたら、boardファイルをAutodesk社の`EAGLE`で開きます。

`EAGLE`をAutodeskのアカウントと連携させておくと、`EAGLE`上の3DPCBを3DCADソフトの`Fusion 360`に送ることができます。

↓矢印のところから

![スクリーンショット (159).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/4d12f1cb-2da1-0787-d1e0-3924caba7662.png)

以下のようなダイアログが出てくるので、それに沿って進めていくと簡単にエクスポートすることができます。

![スクリーンショット (160).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/37328c25-7567-40a2-a941-acb179b147cd.png)

## 3DCADでのデザイン

今度はこれを`Fusion 360`で開きます。

![スクリーンショット (161).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/2c37677a-d2a1-96f3-22d1-da1c9c17120f.png)

あとはこれを元に3DCAD上でデザインを進めて行きます。

出来上がったのが、以下のようなモデルです。

![スクリーンショット (168).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/cb2099db-1044-fdc7-60a9-89dbb676e048.png)

透けて見えているのがAdafruit Trinkey QT2040本体です。

上面に一枚、下面にもう一枚の覆いがあり、USBポート部分にもカバー(キャップ)があります。
上面のカバーとキャップにはストラップホルダーが用意されていて、キャップを無くさないようにしています。

# 完成へ

上記の3つのオブジェクトを3Dプリンタで印刷しました。

![P3220008.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/1987fd9f-dc0a-f588-34b1-1c67370e14d6.jpeg)

さらに↓これらの細かい部品を用意し、本体と組み合わせます。
(Φ2のビス・ナット・スペーサーとボールチェーン)

![P3220013.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/1e3d956d-791a-8cb5-eeba-bfad3ec5029e.jpeg)

そして遂に、**完成品がこちら!!**

![P3220017.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/4df56889-9347-a671-fcb3-9dddacbdab3a.jpeg)

![P3220019.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/7e546dea-4d6f-5175-effc-d15a1a56a99c.jpeg)

![P3220015.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/183170/69492d95-b1fa-3691-e51c-630566f87856.jpeg)

我ながら、非常に上手くできたと思っています👍

# 考察・感想

実際に何度か現場で使用してみましたが、**めちゃくちゃ便利です!!**
やはり長くてランダムで覚えられないようなパスワードにはとても有用だと思います。

前回のラズパイピコを使う方法も含め、非常に便利なデバイスだと思うので是非みなさんも作ってみて下さい!!