RaspberryPiを使って入退室管理システム作ってみた！

# 概要
私が所属している研究室は人が少ない！
これではきっと研究も余り進んでいないはずだ！！（偏見）
ということで、何かと便利な入退室管理システムを作ってみたら以外と面白かったのでそれについて触れていきたいと思います。

# 環境
- Ubuntu 22.04 LTS
- Raspberry Pi 4 Model B
- RC-S380/S
- Python 3.10.12

# 準備
1. NFC/FeliCaリーダーをUSBでRasPiに接続
1. 端末で`lsusb`を打ち込んで下記が出力されれば認識完了！

    ```
    Bus 001 Device 003: ID 054c:06c1 Sony Corp. RC-S380/S
    ```

1. nfcpyをインストール

    ```
    $ pip install -U nfcpy
    ```


## 学生証を中身を見てみる
以下が学生証の中身を見るコードになります。
```python:dump.py
import nfc

def on_connect(tag):
  print(tag)
  for i in tag.dump():
    print(i)
clf = nfc.ContactlessFrontend('usb')
clf.connect(rdwr={'on-connect': on_connect})
```

千葉工業大学の学生証だと以下のような出力が出ました。
```
Type3Tag 'FeliCa Standard (RC-SA00/1)' ID=01130300401E9A0A PMM=033242828247AAFF SYS=81E1
System 81E1 (unknown)
Area 0000--FFFE
  Random Service 64: write w/o key & read w/o key (0x1009 0x100B)
   0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
   *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
   0002: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
  Random Service 68: write w/o key & read w/o key (0x1109 0x110B)
   0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
   *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
   0002: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
  Random Service 72: write w/o key & read w/o key (0x1209 0x120B)
   0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
   *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
   000F: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
  Random Service 76: write w/o key & read w/o key (0x1309 0x130B)
   0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
   0001: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
  Area 2000--20FF
    Random Service 128: write with key & read w/o key (0x2008 0x200B)
     0000: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX |XXXXXXXXXXXXXXXX|
     0001: 30 33 33 31 30 30 30 30 31 20 20 20 20 20 20 20 |033100001       |
     0002: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 |                |
    Area 2100--21FF
    Random Service 132: write with key & read w/o key (0x2108 0x210B)
     0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
     *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
     0002: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
    Area 2200--22FF
    Random Service 136: write with key & read w/o key (0x2208 0x220B)
     0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
     *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
     0002: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
    Area 2300--23FF
    Random Service 140: write with key & read w/o key (0x2308 0x230B)
     0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
     *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
     0003: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
    Area 2400--24FF
    Random Service 144: write with key & read w/o key (0x2408 0x240B)
     0000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
     *     00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
     0003: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
    Area 2500--25FF
    Random Service 148: write with key & read w/o key (0x2508 0x250B)
     0000: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX |XXXXXXXXXXXXXXXX|
     0001: 30 33 00 00 30 30 30 30 20 20 20 20 20 20 20 20 |03..0000        |
     0002: 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 |                |
    Area 3000--30FF
    Random Service 192: write with key & read w/o key (0x3008 0x300B)
     0000: XX XX XX XX XX XX XX XX XX 00 00 00 00 00 00 00 |XXXXXXXXX.......|
     0001: 31 33 31 30 31 30 00 00 00 00 30 30 30 30 30 30 |131010....000000|
     0002: 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 30 |0000000000000000|
     0003: XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX XX |XXXXXXXXXXXX....|
     0004: 00 00 00 00 00 00 00 00 00 00 00 00 31 20 20 20 |............1   |
```

（xxxの部分はプライバシーとして伏せ字という意味で使用しています。）
***どこに学籍番号があるんじゃ！***
っとなった方が多いかと思いますので解説して行きます。
まず、初めに下記のような項目でNFCカードの番号は決まっています。（この表は[こちらの記事](https://qiita.com/h_tyokinuhata/items/2733d3c5bc126d5d4445)を参照して引用しました）
| 項目 | 意味 |
| ---- | ---- |
| Type3Tag | FeliCaで読み取れることを示す |
| RC-SA00/1 | NFCカードのICチップの型番<br>技術情報対象製品一覧から確認することが可能 |
| ID | IDmのこと<br>NFCリーダー/ライターが通信相手のカードを識別するための製造ID<br>上位2byteが製造者コード、続く6byteがカード識別番号 |
| PMM | PMmのこと<br>NFCリーダー/ライターが通信相手のカードの種別と性能を識別するためのパラメータ |
| SYS | システムコード<br>システムを識別するためのコード |
| System<br>Area<br>Service<br>Block | 入れ子構造。Blockに書き込みや読み出しができる16byteの値が格納されている |
| Random Service | read w/oで読み込み書き込み可を示す |

# 入退室管理
研究室の同期が既にQRコードで入退室管理システムを作成していたのでそれと組み合わせたいと思います！
千葉工業大学の学生証ではServiceコードが128のBlockコードが0に学籍番号がASCIIコードの16進数で格納されていました。ちなみに、それ以外の番号はよくわかりませんでした！
```main.py
class NFCReader:
    def __init__(self):
        self.data_num = None
    def connected(self, tag):
        idm, pmm = tag.polling(system_code=0x81e1)
        studentcard_pmm = bytearray(b'\x03\x32\x42\x82\x82\x47\xaa\xff')
        tag.idm, tag.pmm, tag.sys = idm, pmm, 0x81e1
        if studentcard_pmm = tag.pmm:
            sc = nfc.tag.tt3.ServiceCode(128, 0x0b)
            bc = nfc.tag.tt3.BlockCode(0, service = 0)
            data = tag.read_without_encryption([sc], [bc])
            self.data_num = data.decode('ASCII')
            self.data_num = self.data_num[2:9]
```
以上のコードはPMmを指定して千葉工業大学以外のカードは処理しないようにしています。その後、ServiceコードとBlockコードを指定してASCIIコードを取得、文字列に変換して一部切り取っています（欲しい学籍番号が7桁のでありそのままだと要らない値も受け取ってしまうため）。
以上の処理後に学籍番号のリスト内に`self.data_num`を探索し、あれば入室or退室とすれば、できたも同然である！

# 参考資料
この記事は以下の記事を参考にして書かせていただきました。

https://cysec.ise.ritsumei.ac.jp/2022/06/13/%E7%AB%8B%E5%91%BD%E9%A4%A8%E3%81%AE%E5%AD%A6%E7%94%9F%E8%A8%BC%E3%81%AE%E8%A9%B1/

https://qiita.com/h_tyokinuhata/items/2733d3c5bc126d5d4445

https://qiita.com/irutack/items/61a783eb9d5c78d5a3f6