WEBアプリでRFIDシステム はじめの一歩 その2

WEBアプリ はじめの一歩

以前、「WEBアプリでRFIDシステム はじめの一歩」を掲載いたしました。これで、もうちょっと詳しい表示をするものがあったほうがいいという声がありましたので、CSV表示のページをもうちょっと工夫したものを紹介します。

リーダライタからのデータ送信されてきたデータを受信するIISのスクリプトは「WEBアプリでRFIDシステム はじめの一歩」のほうをご覧ください。

IISはWindows11にも搭載されており、Windows10でも11でも基本的に同じように使えます。

RFIDシステムは、導入時にうまく読み取りできるか、ICタグやアンテナの向きなど、数日間設置してみてテストすることも多いですが、そんなとき手軽に読み取りの確認をするといった用途にも活用できるでしょう。

今回のシステム想定例

今回の想定システムイメージです。

リーダライタ設定

MRU-F7100JP, MRU-F5100JPやFRU-F4025Plus等のリーダライタ側の設定です。詳しくは各々の製品のマニュアルを参照してください。

送信先設定

項目内容
プロトコルhttp
メソッドpost
IPアドレス/ホスト名192.168.209.100
パス名/test/test.asp
フォーマットquery
ポート番号80
Keep-Alive有効

連続モード設定

デフォルト設定のままでも大丈夫ですが、同じデータが送信されるのを止めたい場合は、重複チェック機能の設定で同じICタグの送信を削減できます。

動作モード変更(読み取りスタート)

動作モードを「連続モード」に変更します。

動作モードを「連続モード」に変更すると、リーダライタはICタグの検知をはじめます。ICタグを検知するとそのデータを、上の送信先設定で設定したWEBサーバ(192.168.209.100)に送信します。

その他、細かいアンテナ設定や送信データ設定などは割愛します。

結果確認

動作モードを連続モードに変更すると、ICタグの読み取りと、検知したICタグデータの送信が行われ、C:\inetpub\wwwroot\test ディレクトリに、csvファイルが生成されます。

>>データを受信するスクリプトは前回「WEBアプリでRFIDシステム はじめの一歩」をご覧ください。

今回は日付をファイル名にするようなスクリプトですので、2023年5月1日であればdata20230501.csv といった名称のcsvファイルが生成され、同じ日であれば、最後にデータは追加されていきます。

EXCELやメモ帳

csvファイルですので、マイクロソフトのEXCELや、Windowsのメモ帳アプリで内容を確認できます。

生成されるcsvファイル中のデータ例   ファイルネーム: data20230501.csv

※CSVの内容は1番目の項目が、サーバで付加した日付で、2番目の項目の「TAG」以降がリーダライタから送信されてきたデータです。データの内容・意味につきましてはリーダライタのマニュアルを参照してください。

2023/05/01 17:00:54,TAG,1,20180101090003660,3000,1,-516,E2806894000050028A4304AF,1
2023/05/01 17:00:54,TAG,1,20180101090003714,3000,1,-510,E2806894000040029142A520,1
2023/05/01 17:00:54,TAG,1,20180101090003769,3000,1,-516,E2806894000050028A4304AF,1

参考:csvファイルを閲覧するページ

取得されたデータの活用は、実運用時にはいわゆる業務システムの部分ですが、以下、簡単に確認していただくためにcsvファイルの表示させるWEBページ例を示します。

例:

1.以下の内容を「test3.html」というファイルで保存

2.csvファイルと同じディレクトリ、今回の例であれば、c:\inetpub\wwwroot\test ディレクトリにおく。

3.ブラウザのアドレス欄にhttp://192.168.209.100/test/test3.html と入力して開く。

4.csvファイル名を例:data20230515.csv といった生成されたファイル名に修正して、[表示開始]をクリック。

これで指定秒おきに画面が更新され、csvファイルにたまった直近(指定秒以内)のデータの数量と、明細のPC,EPCが表示されます。重複も含みます。

test3.html のコード

<!DOCTYPE html>
<html>
<head>
<!--
【注意】CSVファイルの要素順は1番目:時刻、 5番目pc、8番目:EPC
-->

  <meta charset="utf-8">
  <title>Test CSV Reader3</title>

  <!-- フォントサイズ等はここを修正 -->
  <style type="text/css">
    #count { color : #0000FF; }            /* 数量 */
    div#tagcountDisp {font-size : 20em;} 
    #csv { color : #a52a2a; }              /* 明細 */
    div#csvDisp { font-size : 2em; } 
  </style>

</head>
<body>
  <h1>Test CSV Reader3</h1>
  <form>
  <button type=button onclick="startload();" id=startButton>表示開始</button>  <input type=button value="停止" onClick="stopload();" id=stopButton disabled>  <input type=button value="1回表示" onClick="onceload();" id=onceButton >   csv-file <input type=text value="test.csv" id=csvfile> 最新<input type=text size=3 value="30" id=withinsec>秒のデータ表示 画面更新間隔<input type=text size=3 value="3" id=reloadsec>秒  <button type=button onclick="document.getElementById('count').style.display = 'none';">数量:非表示</button> <button type=button onclick="document.getElementById('count').style.display = 'block';">数量:表示</button>  <button type=button onclick="document.getElementById('csv').style.display = 'none';">明細:非表示</button> <button type=button onclick="document.getElementById('csv').style.display = 'block';">明細:表示</button> 
  </form>
  <div id="timestamp">Last loaded at timestamp</div>
  <section id="count">数量 
  <div id="tagcountDisp" >-</div>
  </section>
  <section id="csv">明細
  <div id="csvDisp" ></div>
  </section>
  
  <script>

    // 数量を表示するdivタグ
    tagcountDispElem = document.getElementById("tagcountDisp");

    // テキストを表示するdivタグ
    csvDispElem = document.getElementById("csvDisp");

    // 時刻を表示するdivタグ
    timestampElem = document.getElementById("timestamp");


    // CSVを読み込んで表示する関数
    function loadCSV() {

      // csvファイルのパス
      const csvPath = document.getElementById("csvfile").value;



      // XMLHttpRequestオブジェクトを作成
      const xhr = new XMLHttpRequest();

      // GETリクエストを送信
      xhr.open("GET", csvPath);

      // キャッシュを使わせない
      xhr.setRequestHeader('Pragma', 'no-cache');
      xhr.setRequestHeader('Cache-Control', 'no-cache');
      xhr.setRequestHeader('If-Modified-Since', 'Thu, 01 Jun 1970 00:00:00 GMT');

      // レスポンスの形式を指定
      xhr.responseType = "text";

      // リクエスト完了時の処理を定義
      xhr.onload = function() {
        if (xhr.status === 200) {
          // レスポンスのテキストを取得
          const csvText = xhr.response;

          // 改行で分割して配列にする 最後空を削除
          let csvLines = csvText.split("\n");
          csvLines.pop();

          // 現在時刻
          const now = new Date();

          //明細表示,数量カウント初期化
          let csvDispElemTmp = '';
          let tagcount = 0;

          while(csvLines.length > 0){
             // 配列の最後の要素を取得し、カンマで分割
             const lastArray = csvLines.pop().split(',');

             // 最初の要素を時間として扱い、Dateオブジェクトに変換
             const timeString = lastArray[0];
             const time = new Date(timeString);

             // 時間の差をミリ秒で計算し、指定秒以内か判定
             const diff = Math.abs(now - time);
             if (diff <= withinsec * 1000) {
               // 明細テキスト
               csvDispElemTmp += lastArray[4] + ' ' + lastArray[7] + "<br>";
               // 行数カウント
               tagcount++;

             } else {
               break;
             }
          }

          // 数量をdivタグに代入して表示
          if( tagcount > 0 ){
            tagcountDispElem.innerHTML = tagcount ;
          } else {
            tagcountDispElem.innerHTML = '-';
          }

          // 明細をdivタグに代入して表示
     csvDispElem.innerHTML = csvDispElemTmp;


          // 時刻を表示
          timestampElem.textContent = "Last loaded at " + now.toLocaleString();
        }
      };

      // リクエストを送信
      xhr.send();
    }

    var IntIDloadCSV = 0;


    function startload(){

      //ボタン有効無効切り替え
      document.getElementById("startButton").disabled = true;
      document.getElementById("stopButton").disabled = false;

      // 直近秒 指定
      withinsec = Number(document.getElementById("withinsec").value);
      if( withinsec < 1 ){ withinsec = 30;}

      // 更新秒 指定
      reloadsec = Number(document.getElementById("reloadsec").value);
      if( reloadsec < 1 ){ reloadsec = 3;}

      // CSVの読み込み実行
      loadCSV();

      // スタート 指定秒ごとに読み込みを繰り返す
      IntIDloadCSV = setInterval(loadCSV, reloadsec * 1000);

    }


    function stopload(){

      //ボタン有効無効切り替え
      document.getElementById("startButton").disabled = false;
      document.getElementById("stopButton").disabled = true;

      // 停止
      clearInterval(IntIDloadCSV);

    }

    // 1回だけCSVを読み込んで表示実行
    function onceload(){

      // 直近秒 指定
      withinsec = Number(document.getElementById("withinsec").value);
      if( withinsec < 1 ){ withinsec = 30;}

      loadCSV();

    }

  </script>
</body>
</html>

test3.htmlの画面例

まとめ

ICタグを製品やパレットなどに貼付し、そのデータを検知して、進捗や入庫・出庫など管理をおこなうといったケースも多いかと思います。これをWEBアプリシステムにする際のまずは、はじめの簡単なcsvファイル化と状況表示の試行を紹介させていただきました。

今回は前回のCSVデータをつかって表示をさせていますが、アンテナ番号やリーダライタIDの情報も含まれていますので、それらをhtml/JavaScriptを活用して切り分けて、アンテナ別・リーダライタ別の表示も可能です。

もちろん、実運用では、csvファイルの生成でなく、データベースに格納するようなシステムにしたり、負荷を考えたシステムにする必要がありますので、WEBアプリに長けたシステム会社様にご相談ください。今回は単純にCSVファイルに追記していっていますだけですが、多くの場合、読み取りデータは、オンプレであればSQL Server 、Oracle、PostgreSQLといったデータベースにまずは格納します。オンプレなサーバに加えて、多拠点であれば、さらにクラウドを活用するのもよくやられる手法です。WEBサーバもnginxやApache、言語もpython、PHP、Ruby、JAVA、その他各種のフレームワークの活用が一般的です。

※今回の記事の内容はあくまでも実験・テスト用です。記事の利⽤により、万が⼀利⽤者に何らかの損害が⽣じても当社は責任を負わないものとさせていただきます。利⽤者の責任においてご活⽤くださいますよう、お願い申し上げます。

固定式リーダライタ MRU-F7100JP
UHF帯RFIDリーダライタ

固定式、ハンディ、ゲート型、トンネル型など各種取り揃え

HF帯RFIDリーダライタ

卓上タイプ、タッチパネル端末など各種取り揃え

パッケージシステム

RFIDシステムのスモールスタートをサポート

ICタグ・ICカード

金属対応タグ、リネンタグ、耐熱タグなど各種取り揃え


RFID所在/通過管理スタートアップ
RFID持ち出し管理スタートアップ
RFID通過方向検知装置