アイキャッチ画像

Socket.IO×WebUSBでリアルタイムに教室スタッフの人数が分かる打刻システムを作ってみた

公開:2023/12/12

更新:2023/12/13

この記事はデジクリ Advent Calendar 2023 12日目の記事です。
デジクリは芝浦工業大学の創作サークルです。
デジクリについて、詳しくはこちらのサイトをご覧ください。
11日目の記事は19th きたぴーさんの「こわくない Meta Quest 開発」です。

目次

  • はじめに
  • 事の経緯
  • 何を作ったか
    • カードリーダー
    • スタッフ一覧
  • システムの構成
  • ロジックの解説
    • 学生証を読み取る
    • 入退室処理を行う
  • 工夫したところ
  • 大変だったところ
  • おわりに
  • 参考文献

はじめに

先週に引き続きまた会いましたね、19th さかと申します。先週は快活班だったので今週はSystemDevelopment班です。

コードを見せながら詳細に解説している記事っぽいタイトルですがコードを見せながらの解説はありません。ごめんなさい。代わりに図と文章で処理の流れを解説していきます。

今回は芝浦祭当日に使っていたシフト管理システムの仕組みを解説していきます。PG班じゃなくても分かりやすいようにできるだけゆるめの文章と図で書いたので肩の力を抜いてゆっくりしていってね。

事の経緯

例年、芝浦祭のデジクリブースではデジクリ部員が制作した作品の展示を行っており、1日約20人ほどの部員がスタッフとして作品の説明をしていました。しかし、デジクリは部員の数が100人以上ととても多く、さらに部員それぞれの班(活動のカテゴリ)も「イラスト」「プログラミング」「DTM」「3DCG」「Movie」「VTuber」「文字書き」などかなり幅広いため、「今教室にいる誰が、どんな作品についてお客さんに説明できるのか」ということを1人1人把握しきれないという問題がありました。

そこで、スタッフの入退室をシステムで自動的に管理させることで上記の問題を解決しようという話になりました。

何を作ったか

シフト管理システムの外観

こちらが今回作成したシフト管理システムです。制作期間は約1ヶ月でした。

主な機能としては学生証をタッチするだけで簡単にスタッフの入室・退室の記録ができたり、教室内にいるスタッフの人数を各班ごとに確認したりすることができます。Webアプリとして動作しているので、離れた場所からスマートフォンでスタッフの状況を確認することもできます。

芝浦祭当日はこれをスタッフの休憩スペースの入り口に置き、入退室時に学生証をタッチしてもらうことで教室内に誰がいるかを管理していました。使ってくれてありがとう。

このシステムはカードリーダースタッフ一覧の2つのページで構成されていて、それぞれ異なった用途を持っています。次は各ページの用途・機能・使い方をまとめて紹介します。

カードリーダー

スタッフの入退出情報の記録を行うためのページで、FeliCaリーダーとセットで使います。

芝浦の民なら何だかこの画面に見覚えがあると思いませんか?お察しの通り、芝浦工大の学内で使用されている(いた)打刻装置とほぼ同じ見た目をしています。勝手にパクってごめんなさい

使い方も元ネタの打刻装置を踏襲しており、

1.「入室」または「退出」を押して選択する
2.学生証をFeliCaリーダーにかざす

の2ステップだけで簡単に入退室情報を記録することができます。

ちなみにこの見た目にした一番の理由は、「機能が同じなら見た目も同じにした方がぱっと見ただけで使い方や目的を理解してもらえるのでは?」と思ったからです。分かりやすさは大事。次点で「見た目の部分を作るのが簡単そうだったから」。

スタッフ一覧

現在のスタッフの状況を確認するためのページです。

各班に何人のスタッフが教室にいるのか、英語で応対できるスタッフは何人いるのか、教室にいないスタッフは何人いるのかといった情報をリスト形式でひと目で確認することができます。班のブロックをタッチすることで人数に加えてそのスタッフの名前(ニックネーム)も表示させることができます。

またカードリーダーでスタッフの入退室情報が更新されると、こちらの一覧にもリアルタイムで自動的に反映されるようになっているので常に最新の情報を確認することができます。すごい(自画自賛)。

このページはスマートフォンで見ることを想定していたので、必要な情報が1画面にすべて収まるようにすることと可能な限り少ない操作で使えることを意識しました。

システムの構成

システム構成図

上の図はシフト管理システムに利用した技術たちをざっくり表した図です。簡単に枠組みを説明すると、フロントエンドは主に端末側で使われる目に見える部分、バックエンドは主にサーバ側で使われる目に見えない部分、みたいな認識でだいたいOKです。

下はそれぞれの適当な説明です。あまりにも中身が無い説明なので、「よく分かんない!」って人は「へ~色んなプログラムや技術が使われてるんだな~」くらいの認識で読み飛ばしてしまってOKです。

  • フロントエンド & バックエンド
    • TypeScript: プログラミング言語
    • Next.js: フレームワーク(Webサイトやサーバを構築するための枠組み)
  • フロントエンド
    • React: UIを書くためのライブラリ
    • Chakra UI: UIの見た目や触った時の動きなど
    • WebUSB API: USBで接続されたカードリーダーをブラウザから操作する
  • バックエンド
    • Socket.IO: WebSocket(クライアント・サーバ間のリアルタイムな双方向通信)に利用
    • SQLite: データベースを操作するためのソフトウェア
    • Prisma: ↑と組み合わせてデータベースを扱いやすくするためのライブラリ
  • コンテナ
    • Docker: ソフトウェア群を「コンテナ」として仮想環境上でまとめて実行できる
  • インフラ
    • Cloudflare Tunnel: アプリをインターネット上からアクセスできるようにする

ロジックの解説

ここはちょっと真面目に書きます。

シフト管理システムの機能を大きく「学生証を読み取る」「入退室処理を行う」の2つに分けて、それぞれ段階的に解説していきます。

学生証を読み取る(クライアント側の処理)

学生証から学籍番号を読み出す処理のフローチャート

上はクライアント側で行われる、学生証を読み取ってサーバに送信する処理のフローチャートです。

1. ポーリング

学生証の情報を読み取る前に、まずはカードリーダーに学生証がかざされているかを確認する必要があります。そこで、定期的に繰り返しカードリーダーに「学生証がタッチされたか?」と尋ね、学生証を検出したタイミングで学生証内の情報の読み取りを開始します。このような手法をポーリングといいます。(追記:より正確には、FeliCaリーダーを操作するコマンドの1つにカードの検出を確認するためのPollingというコマンドがあり、それを繰り返し実行させることでポーリングの挙動を実現しています ややこしいね…)

ポーリングの解説画像

文章だけだと分かりづらいと思うので、ポーリングの仕組みを図にしてみました。

学生証がタッチされていない場合は繰り返し「学生証ある?」「学生証ないよ」というやり取りを繰り返します。

「学生証ある?」と尋ねて学生証が見つかった場合は、続けて学籍番号を読み取るように指示を出します。そして、一連の流れが終わるとまた「学生証ある?」と尋ねる処理に戻ります。

2. 学籍番号を読み取る

カードリーダーに学生証がかざされているのを確認できたら、続けてその学生証に保存されている学籍番号を読み取ります。

ざっくり学生証の仕様を要点だけ説明すると、芝浦工大の学生証はFeliCaという規格の非接触ICカードでできていて、中のメモリに任意の情報を保存することができるようになっています。

カードの中にあるメモリにはカード固有のID番号(IDm)と学籍番号が保存されているので、カードリーダーに「メモリ内の学籍番号が保存されている領域を読み取って、読み取れた学籍番号を教えて!」と指示してやることで学籍番号をカードから読み取ることができるのです。

3. アプリケーションサーバに送信

学生証の中の学籍番号が読み取れたら、アプリケーションサーバに「学籍番号が〇〇の人の状態を〇〇にして」という要求を送信します。

サーバが要求を受け取った後どのような処理が行われるのかについては次項で解説します。

4. 処理の結果を表示

サーバ側での処理が終わると「成功」または「失敗」が結果として送られてくるので、それに応じて画面上部に上の画像のようなメッセージを表示します。これで入退室が正しく行えたかどうか確認することができます。

ここまで来たらフロントエンド側の処理は全て完了なので、また最初のポーリングに戻って次の学生証の読み取りを待機します。

入退室処理を行う

ここからは学生証を読み取った後の処理について説明します。

入退室履歴を書き込む処理のフローチャート

上は主にサーバ側で行われる、学籍番号をもとに入退室履歴を書き込む処理のフローチャートです。

ここでは擬似的なデータベースの表を用意して、データの動きを見せながら解説していきます。

「スタッフ」の表

「スタッフ」のデータベース

「入退室履歴」の表

「入退室履歴」のデータベース

  • 「スタッフ」のデータベースには、スタッフの項目ID、学籍番号、名前、所属班、英語応対の可否が書き込まれている
  • 「入退室履歴」には、スタッフの項目、入退室の状態、日時が書き込まれる

とりあえず上のようなデータが用意されていて、学籍番号が「xx00001」のスタッフの状態を「入室」にすると仮定して話を進めていきます。

1. 学籍番号からデータベースを検索

サーバとデータベースのやり取り

まず、「学籍番号がxx00001の人のステータスを入室にする」という要求を受け取ったサーバは、データベースに対して「学籍番号がxx00001のスタッフについて探して」と問い合わせを行います。

スタッフの情報が見つかった場合、データベースはアプリケーションサーバに「ID」「名前」「所属班」「英語応対の可否」のデータを返却します。

もし見つからなかった場合は、「そんな人見つからないよ」とエラーを応答し、処理が終了します。

2. 入室/退室履歴をデータベースに書き込む

次に、サーバはデータベースに「入退室履歴にID=0, 状態=入室のデータを追加して」と問い合わせを行います。

すると、「入退室履歴」のデータベースにスタッフのIDと状態、現在の日時が書き込まれます。

データが書き込まれた後の入退室履歴

3. 一覧ページに更新を通知

実際に動いている様子のアニメーション

最後に、一覧ページをリロードしなくても自動的に入室・退室が反映されるように、サーバは一覧ページに対してWebSocketで「ID=0, 名前=さか, 所属班=[PG班, イラスト班] の人が入室したよ」という情報を送信します。

一覧ページがこれを受け取ると、入室したメンバーの名前を所属している「PG班」と「イラスト班」のリストに追加し、逆に「外出中」のリストから削除します。

このようにメンバーの入退室の状態が書き換えられる度に通知を送信して一覧を書き換えることで、リアルタイムなスタッフ一覧の表示を実現しています。

工夫したところ

今回シフト管理システムを開発する上で工夫した点は、なるべくシンプルな見た目にして誰でも直感的にシステムを利用できるようなUI設計を行ったことです。当日も簡単な説明書きを用意しただけで、質問攻めになることなく運用できていました。

また、部員のデータを簡単にデータベースに取り込める対話型のスクリプトも作成しました。これにより、Google Formsで収集したデータを簡単に扱えるようになり、当日のデータの取り込みも円滑に行うことができました。

大変だったところ

Next.jsやReact、NFC通信など、今回使用した技術についてはほとんどミリしら、どころか全く知らないまま開発をスタートしたので、必要な知識について調べ調べ作っていくのが大変でした。そのせいで芝浦祭前日に一覧ページの描画が無限ループする重大なバグが発生してしまい大急ぎで修正に追われるなど、なかなかピンチを極めていました。

ともあれ当日は問題なく稼働できていてよかったです。

さいごに

以上が芝浦祭で運用していたシフト管理システムの解説でした。長々と書いてしまいましたが楽しんでいただけたら幸いです。

もし需要があればもっと詳細に書いたバージョンを出すかもしれません。n年後とかに気が向いたら。

ここまで読んでくださりありがとうございました!ソースコードはGitHubにアップロードされているので興味があれば読んでみてください。

明日の記事は19th ケトコンさんの「継続的な努力=こなせる目標の連続体」です。
お楽しみに!

参考文献

  • 株式会社ブリリアントサービス, "NFC Hacks - プロが教えるテクニック & ツール", オーム社, 2013.