WebUSBとRaspberryPiでNFCカードリーダーを使う


はじめまして。Qiita初投稿になります。

現在、勤怠の入力がスプレットシートへの手入力で行っており、入退室カードでの勤怠の打刻ができれば手間も減るのではと考えました。
ひとまず、NFCカードリーダーで入退室カードをスキャンしてIDを取得するまでを書いてみます。

最終的には勤怠システム的なものも作って連携できればと思っています。

# 今回やること
Raspberry PiのセットアップからRaspberry Piに接続したUSBのカードリーダーで入退室カードの情報を読み取るところまで

# 使ったもの
Raspberry Pi3 Model B
PaSoRi RC-S380
MicroSD 32GB

SDカードリーダー（USB）
入退室用で貸与されているNFCカード
iMac(mojave 10.14.6)
Chromiumブラウザ(version 74.3729.157)

# さっそくやってみる

### Raspberry Pi用のSDカードをフォーマット
- SDカードリーダー(USB)にMicroSDカードを挿入しiMacへ接続する。

- ディスクユーティリティからSDカードをフォーマットする。
`ディスクユーティリティ > 対象のドライブを選択（SDカード） > 消去`

- フォーマット後にマウントされているので、アンマウントする。
 まず、対象を間違えないように確認する。

```console
$ diskutil list
/dev/disk0 (internal):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                         121.3 GB   disk0
   1:                        EFI EFI                     314.6 MB   disk0s1
   2:                 Apple_APFS Container disk2         120.9 GB   disk0s2

/dev/disk1 (internal, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      GUID_partition_scheme                        *2.0 TB     disk1
   1:                        EFI EFI                     209.7 MB   disk1s1
   2:                 Apple_APFS Container disk2         2.0 TB     disk1s2

/dev/disk2 (synthesized):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:      APFS Container Scheme -                      +2.1 TB     disk2
                                 Physical Stores disk0s2, disk1s2
   1:                APFS Volume Macintosh HD            89.4 GB    disk2s1
   2:                APFS Volume Preboot                 46.6 MB    disk2s2
   3:                APFS Volume Recovery                510.3 MB   disk2s3
   4:                APFS Volume VM                      2.1 GB     disk2s4

/dev/disk3 (external, physical):
   #:                       TYPE NAME                    SIZE       IDENTIFIER
   0:     FDisk_partition_scheme                        *31.7 GB    disk3
   1:             Windows_FAT_32 boot                    268.4 MB   disk3s1
   2:                      Linux                         31.4 GB    disk3s2
```
今回の場合は `/dev/disk3` がSDカード

`/dev/disk3` をアンマウントをする。

```console
$ diskutil unMountDisk /dev/disk3
```

### Raspbianをインストール

- イメージのダウンロード

https://www.raspberrypi.org/downloads/raspbian/
上記からRaspbianのOSイメージをダウンロードしてくる。
<img width="984" alt="Raspbian ダウンロードページ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474604/897c01c5-4db2-6d1d-a7a6-c2c44cda8a4e.png">

3種類あります。最小構成のRaspbianBusterLiteを使い、必要なものを後でインストールするほうが良いかと思います。
今回はサクッとすすめるためにもRaspbianBusterwithdesktopをダウンロード。

- RaspbianをSDカードに展開

ダウンロードされたファイルはzipなので、解凍してからSDカードへイメージを書き込む

```
sudo dd if=/Users/{ユーザ名}/Downloads/2019-07-10-raspbian-buster.img of=/dev/rdisk3 bs=1m
```
終わったら取り外してからRaspberry Piに挿入して起動し、言語やパスワードなどの設定を行いネットワークへ接続する。

- ソフトウェアを更新

```console
$ sudo apt-get update
$ sudo apt-get upgrade
```

- vimのインストール

エディタを開くと互換モードになってしまうので、vimをインストールしておく。

```console
$ sudo apt-get install vim
```

### MacからSSHでアクセスできるようにする
RaspberryPiにもディスプレイをつけているが、３．５インチと小さいため見にくい。
MacからSSHでアクセスできるようにする。

- RaspbianのSSHを有効にする。

```console
$ sudo raspi-config
```
Interfacing Options > SSH > Yes(はい)
![1566377231.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474604/6f7232b7-a8ff-1678-fd0e-101014db48a5.jpeg)

- 社内のみの利用なのでとりあえずパスワード認証のみで接続できるようにする。

SSHの設定を変更する。

```console
$ sudo vim /etc/ssh/sshd_config
```

パスワード認証を有効にする（コメント化されているはずなので解除）
`#PasswordAuthentication yes` → `PasswordAuthentication yes`

- 保存してsshdを再起動する。

```console
$ sudo systemctl restart sshd
```

- MacからSSHでログインする

```console
ssh pi@{IPアドレス}
```
これでMacからコンソールを操作できるようになりました。
※ IPアドレスはifconfigなどで調べてください。今後アクセスすることを考慮して、固定化しておくほうが良いです。

#### カードリーダーの設定する

- Pasori RC-S380をRaspberryPiへ接続する。
![IMG_0801.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474604/69baeb92-04a6-065c-6bc6-c4b89fab5552.jpeg)

接続されていることを確認。

```console
$ lsusb
Bus 001 Device 004: ID 1ea7:0064 SHARKOON Technologies GmbH 
Bus 001 Device 011: ID 054c:06c3 Sony Corp. RC-S380
Bus 001 Device 005: ID 0424:7800 Standard Microsystems Corp. 
Bus 001 Device 003: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 002: ID 0424:2514 Standard Microsystems Corp. USB 2.0 Hub
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
```

```console
Bus 001 Device 011: ID 054c:06c3 Sony Corp. RC-S380
```
Pasori RC-S380が接続されていることが確認できた。

- WebUSBからアクセスできるようにする。

このままではPasori RC-S380へアクセスできず、`Security Error:Access denied〜`というエラーがでる。
これは、rootユーザー以外のUSBへのアクセスできないのが原因。
現在ログインしているpiユーザーでもアクセスできるように設定を追加する必要があります。

- Pasori RC-S380のベンダーIDとプロダクトIDを調べる。

```console
Bus 001 Device 011: ID 054c:06c3 Sony Corp. RC-S380
```
`lsusb`で確認した`054c:06c3` ここが `{ベンダーID}:{プロダクトID}`。

- udevのrulesファイルを作成して追記する。

```console
$ sudo vim /etc/udev/rules.d/nfc.rules
```
以下のように追記する。

```console
ATTRS{idVendor}=="{ベンダーID}", ATTRS{idProduct}=="{プロダクトID}", ACTION=="add", GROUP="{対象のユーザグループ}", MODE="660"
```
今回の場合は
`ベンダーID:054c` `プロダクトID:06c3` `対象のユーザグループ:pi`なので以下のようになる。

```console
ATTRS{idVendor}=="054c", ATTRS{idProduct}=="06c3", ACTION=="add", GROUP="pi", MODE="660"
```
※ ユーザの所属グループの確認方法

```console
$ groups {ユーザ名} 
```

- udevの再起動をしてから、RC-S380をRaspberryPiから抜き差しする。

```console
$ sudo systemctl restart udev
```

これでpiグループから対象のRC-S380へのアクセスができるようになりました。

#### 実際に動かしてみる。

実際にブラウザでアクセスできるか確認する。

- サンプルを作成する。

以下記事を参考にサンプルを作成させていただきました。
>　WebUSBでFeliCaの一意なIDであるIDmを読む
>　https://qiita.com/saturday06/items/333fcdf5b3b8030c9b05

こんな画面をサンプルのhtmlを作りました。
<img width="777" alt="reader.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474604/cd5e2d9a-4348-164d-5177-dd79a6fca8ee.png">

このまま`file://〜`プロトコルでhtmlをChromiumで開くと、USBへのアクセスを行おうとするとエラーが発生します。
`TypeError: Cannot read property 'requestDevice' of undefined`

Chromium側のセキュリティの問題でWebUSBでのアクセスは `localhost` または `https://~` である必要があるそうです。


#### localhostで確認するためにNginxをインストールしてサンプルを動かしてみる

- Nginxをインストール。

```console
$ sudo apt-get install nginx
```
- Nginxを起動

```console
$ sudo /etc/init.d/nginx start
```

- サンプルをNginxのドキュメントルート以下へ配置

```console
$ cd /var/www/html
```

- 作成したサンプルをChromiumから開く。

`test.html`という名前で作成し、Nginxのドキュメントルート直下似配置したので、http://localhost/test.html を開く。

- ChromiumからのUSBへの接続確認が出る。
<img width="699" alt="確認.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474604/54196648-53b1-cbbd-e7e9-f9f5a9afeac9.png">

- NFCカードを読み込み、一意なIDが表示されカードリーダーが使えた。
<img width="718" alt="スクリーンショット 2019-08-21 19.25.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/474604/6732e8bd-27e7-5297-d1b7-15fef0bee260.png">

# おわりに

RaspberryPiを使ってカードリーダーでNFCカードのIDを読み取る事ができ、ICOCAやSuicaでも問題なくIDを読み取ることができました。

標準ドライバだと接続できない、OSによっては使えないという記事をいくつか見かけましたが今回は特に問題なく使えましたので、最新のOSでは必要ないのかもしれません。
また、iMacの方にカードリーダーを接続してサンプルをApache上で確認してみたところ問題なく動作しました。

以前からWEBブラウザでUSBだったりBluetoothだったりといろいろできるようになるのは気になってましたので、触る機会が訪れて嬉しいです。
今後は勤怠システムを作って連携したり、他にも色々できそうですので随時やっていきたいところです。

そしてRaspberry Pi4がほしい・・・！