RFIDを使った管理システム

# RFIDを使った出席管理システムの構築

RFID技術を活用して、出席管理を自動化する方法をご紹介します。この記事では、SonyのRC-S380/S NFCリーダーを使用して、出席データを収集し、MongoDBに記録するシステムの作り方を説明します。

## 必要な機材とソフトウェア

- Sony RC-S380/S NFCリーダー
- NFCタグ(Suica)
- Python 3.9
- MongoDB

## システム概要

このシステムは、以下の2つの主要コンポーネントから構成されます。

1. **RFID読み取りプログラム (`rfid.py`)**: NFCリーダーでタグを読み取り、MongoDBに記録します。
2. **Webインターフェース (`web.py`)**: Flaskで構築したWebアプリケーションで、記録された出席データを表示します。

## 環境設定

### MongoDBのインストールと設定

MongoDBはNoSQLデータベースで、以下の公式ウェブサイトからダウンロードしてください。

- [MongoDB公式ウェブサイト](https://www.mongodb.com/try/download/community)
```bash
# MongoDBのセットアップ
mongo
use attendance
db.createCollection("records")
```

### RFID読み取りプログラム (rfid.py)
RFIDタグの情報を読み取り、MongoDBに記録するためのプログラム

```py
import nfc
import pymongo
import datetime

# MongoDBのセットアップ
client = pymongo.MongoClient("mongodb://111.1.1.1:11111/") #自分のアドレスを設定
db = client["attendance"]
collection = db["records"]

# NFCリーダーの初期化
clf = nfc.ContactlessFrontend('usb')

try:
    while True:
        # NFCタグの読み取り
        tag = clf.connect(rdwr={'on-connect': lambda tag: False})
        if tag:
            tag_id = tag.identifier.hex()
            print(f"Detected NFC Tag with ID: {tag_id}")

            # 現在のタイムスタンプ
            timestamp = datetime.datetime.now()

            # データベースに保存
            collection.insert_one({"tag_id": tag_id, "timestamp": timestamp})
            print("Data saved to MongoDB")

except KeyboardInterrupt:
    # ユーザーがプログラムを中断するまでループ
    pass
finally:
    clf.close()
    print("NFC reader closed")
```

### Webインターフェース (web.py)
Flaskを使って構築したWebアプリケーションのコード

```python
from flask import Flask, render_template
import pymongo
import csv

def read_csv_file(filename):
    with open(filename, mode='r', encoding='utf-8') as file:
        reader = csv.DictReader(file)
        return list(reader)


app = Flask(__name__)

# MongoDBのセットアップ
client = pymongo.MongoClient("mongodb://111.1.1.1:11111/") #自分のアドレスを設定
db = client["attendance"]
collection = db["records"]

@app.route('/')
def index():
    # MongoDBから出席記録を取得
    attendance_records = list(collection.find())

    # CSVから学生情報を読み込む
    students_data = read_csv_file('./info.csv')

    # TagIDをキーとして学生情報と出席記録を結合
    for record in attendance_records:
        student_info = next((item for item in students_data if item["TagID"] == record["tag_id"]), None)
        if student_info:
            record.update(student_info)
        else:
            record.update({'name': '-', 'number': '登録なし'})
        

            

    # データをテンプレートに渡す
    return render_template('index.html', data=attendance_records)

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)
```
```index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Attendance Records</title>
    <style>
        table {
            border-collapse: collapse; /* セルの境界を結合 */
            width: 100%; /* テーブルを親要素の幅いっぱいに広げる */
        }
    
        th, td {
            padding: 8px; /* セル内の余白を設定 */
            text-align: left; /* テキストを左寄せにする */
        }
    
        tr:nth-child(even) {
            background-color: #f2f2f2; /* 偶数行の背景色を設定 */
        }
    </style>
    
</head>
<body>
    <h1>Attendance Records</h1>
    <table border="1">
        <tr>
            <th>number</th>
            <th>name</th>
            <th>tag_id</th>
            <th>Timestamp</th>
            
        </tr>
        {% for record in data %}
        <tr>
            <td>{{ record.number }}</td>
            <td>{{ record.name }}</td>
            <td>{{ record.tag_id }}</td>
            <td>{{ record.timestamp }}</td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>
```
以下のinfo.csvファイルでこのようなデータ(仮)を作成する．
| | | |
|-|-|-|
|name|number|TagID|
|山田太郎|123456|0000000|
|鈴木花子|234567|123456789|
|佐藤一郎|345678|abcdefg|



## 実際のWebページの表示
以下は、Webインターフェースを通じて表示される記録のスクリーンショット
![site.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854781/e7e4c2fe-54b8-ec15-879c-567005c22d19.png)