2020年4月22日水曜日

テレワークを応援!RFIDで勤怠報告を自動化する

みなさん、テレワークしてますか。弊社でも昨今の情勢を受け、テレワークでの勤務を推し進めているところです。

さて、テレワーク中は勤怠報告を求められることも多いのではと思います。弊社でも始業時、昼休憩開始時、昼休憩終了時、終業時の1日計4回、メールでの報告を行っています。(そんなのチャットのステータスでいいじゃん、という声もあるかと思いますが、決まりは決まりです)
今まではGmailのテンプレートを使って凌いでいたのですが、この先の見えない状況を考えると4回といえど、重荷になってきます。

そこで、RFIDを使って自動化してしまおうと思います。たぶんこの記事を読んでいる方なら、自宅にRFIDリーダの1台や2台転がっているものと思いますので、ぜひお試しください。

使ったもの


マスプロ電工製RFIDリーダ、RFIDシートアンテナ

こんな感じです。ロープロファイルで机の上に置いておいても邪魔になりません。


Googleスプレッドシート

こんな感じのシートを用意しました。始業時間~終業時間の各列が勤務報告する時間に相当します。その他列はデバッグや判断できない時間帯に読まれた場合に利用します。タグIDのところに勤怠報告に使うタグのIDをセットします。G列にその日にやったことを書いておけば、それを終業時にメールで送信するようにしました。


ちなみに弊社は10:00~15:00がコアタイムのフレックス制で、11:45~12:45がお昼休みとなります。

Google Apps Script

詳しくは他の解説記事にゆずりますが、function doGet(e)という関数を作成すると、HTTP GETでアクセスを受け付けられるようになります。今回はtagId引数に読まれたタグIDを乗っけてアクセスする形にしました。

スプレッドシートのIDを使ってアクセスして、時間に応じて特定のメールを送信する感じにしました。たとえば、8時から10時の間なら業務開始、16時半以降なら業務終了といった感じです。この辺の業務ロジックはスプレッドシート側に設定持たせた方がよかったかもしれません。ソースの一部を抜粋すると、大体こんな感じです。


   
    var id = 'XXXXX';
    var sheet = SpreadsheetApp.openById(id).getSheetByName("シート1");
    
    var registeredTagId= sheet.getRange('B1').getValue();
    
    var tagId = e.parameter.tagId;

    if (tagId == registeredTagId) { // 登録されたタグIDと一致するか
      
      var lastRow = sheet.getLastRow();
      
      var dateNow = new Date();
      
      var lastDate = new Date(sheet.getRange(lastRow, 1).getValue());
      
      var recordRow;
    if (lastDate.getFullYear() == dateNow.getFullYear()
        && lastDate.getMonth() == dateNow.getMonth()
        && lastDate.getDate() == dateNow.getDate()) {
          recordRow = lastRow;
        } else {
          // 当日のレコードが無ければ追加
          recordRow = lastRow + 1;
          sheet.getRange(recordRow, 1).setValue(Utilities.formatDate(dateNow, "JST", "yyyy/MM/dd"));
          sheet.getRange(recordRow, 7).setValue('資料作成');
        }
      
      const recipient = 'recipient@example.jp';
      var subject;
      var body;
      const options = {cc: 'cc@example.jp'}
      if (dateNow.getHours() > 7 
          && dateNow.getHours() < 10) {
        //始業
        recordColumn = 2;
        var workPlan = sheet.getRange(recordRow, 7).getValue();
        subject = 'テレワーク開始連絡(中野)';
        body = `中野です。\n\n今からテレワーク開始します。\n\n <予定作業>\n・${workPlan}\n\nよろしくお願い申し上げます。`;
      } else if ((dateNow.getHours() == 11 && dateNow.getMinutes() >= 45 && dateNow.getMinutes() <= 59)
      || (dateNow.getHours() == 12 && dateNow.getMinutes() >= 0 && dateNow.getMinutes() <= 15)) {
        //休憩開始
        recordColumn = 3;
        subject = '休憩開始連絡(中野)';
        body = '中野です。\n\n今から休憩開始します。\n\nよろしくお願い申し上げます。';
      } else if (dateNow.getHours() == 12 && dateNow.getMinutes() >= 30) {
        // 休憩終了
        recordColumn = 4;
        subject = '休憩終了連絡(中野)';
        body = '中野です。\n\n今から業務を再開します。\n\nよろしくお願い申し上げます。';
      } else if ((dateNow.getHours() == 16 && dateNow.getMinutes() >= 30) 
        || (dateNow.getHours() >= 17)) {
          //終業
          recordColumn = 5;
          var workRecord = sheet.getRange(recordRow, 7).getValue();
          subject = 'テレワーク終了連絡(中野)';
          body = `中野です。\n\nテレワーク終了します。\n\n<実施作業>\n・${workRecord}\n\nよろしくお願い申し上げます。`;
        } else {
          recordColumn = 6;
        }
      
      var recordCell = sheet.getRange(recordRow, recordColumn);
      if (recordCell.isBlank() || recordColumn == 6) {
        recordCell.setValue(Utilities.formatDate(dateNow, "JST", "HH:mm:ss"));
        if (subject != undefined && body != undefined) {
          GmailApp.sendEmail(recipient, subject, body, options);
        }
      }


MANICAコレクタ

MANICAコレクタはこちらからダウンロードいただけます。多くのリーダに対応しておりますので、お持ちのリーダが対応しているかぜひチェックしてみてください。お使いになりたいリーダありましたら、お声がけください。(有償になりますが...)

リーダを追加して、高度な設定を開くと、一番下にWebサーバへ投げるというチェックボックスがあるので、チェックします。隣にGASの公開URLと引数を記述してください。URL中の[タグID]が実際に読まれたタグIDに置換されてHTTP Getされます。ちょっとした注意点としては、httpかhttpsはリストボックスから選択する形なので、URLの//の後ろからテキストボックスにはコピペしてください。


あとはMANICAコレクタのショートカットをWindowsのスタートアップフォルダに作成し、起動時に自動で開始するにチェックを入れておけば準備完了です。次回以降、始業時など、必要なタイミングでタグを読ませれば、自動でメールを送ってくれるようになります。


2020年4月3日金曜日

Bluetooth問題をなんとかする

おかげさまでご好評いただいております棚卸パッケージですが、面倒な問題を抱えております。ハンディリーダとPCの接続方法なんですが、現状はBluetoothかWifiを選択できるようになっています。このBluetoothが結構相性問題があって組み合わせによって接続できなかったり不安点だったりしていました。

昔はBluetoothスタックとして東芝スタックがほとんどの状況で、東芝スタックは安定していたのであまり問題にならなかったんですが東芝スタックを使っているBluetoothドングルというのが少なくなってしまい、他のスタックだと接続できない問題が明らかになってきて何とか東芝スタックのドングルを確保するのに奔走していました。

が、最後の東芝スタック対応ドングルのBT-Micro4-Hが在庫限りとなってしまっておりどうしたもんかなこれ、という状況でした。

この状況を打開するため、目を付けたのがコレ


じゃーん。ESP32ちゃんです。

ESP32のBluetoothは他の案件でも使用していますが結構安定して使えています。ということで通信系はESP32ちゃんに任せてしまって、COMとのブリッジをすることでPCからは単純にCOMポートとしてだけ見える状況にしてしまおうという計画です。

PCからは単にCOMポートにしか見えませんから、Bluetoothスタックがどうのこうのという話はなくなります。Bluetoothが付いていようがいまいが、どんなスタックが入っていようが入っていまいが、とにかくWindowsPCであれば動作するようになります。

というわけでやってみました。
ESP32のプログラムはBluetoothでハンディに接続し、あとはシリアルとBluetoothの通信をブリッジするだけなので簡単です。

#include "BluetoothSerial.h"

static BluetoothSerial SerialBT;
static uint8_t address[6]  = {0xD4, 0xC9, 0x4B, 0x80, 0x3B, 0x89};

void setup() {
  Serial.begin(115200);
  SerialBT.begin("ESP32", true);
}

void loop() {
  if (!SerialBT.hasClient()) {
    if (!SerialBT.connect(address)) {
      while(!SerialBT.connected(10000)) {
      }
    }
  } else {
    while (SerialBT.available() > 0)
      Serial.write(SerialBT.read());
    while (Serial.available() > 0)
      SerialBT.write(Serial.read());
  }
}

従来だと、

ハンディ(とかAndroid)とPCをペアリング → 設定されたCOMポートをエクセルツールに設定

という流れでしたが、

ESP32をPCに接続 → 設定されたCOMポートをエクセルツールに設定

という流れになります。
エクセルツール側はCOMポートとのやりとりということに違いはありませんのでほぼそのままで動きます。
今回Android版で試しましたが、Android側はPCから接続されるかESP32から接続されるかの違いなのでこちらもほぼそのままで動きます。


じゃーん、ちゃんと動きました。

PC <- COM -> ESP32 <- Bluetooth -> Android(SPP)

という組み合わせで動かしてますが、ESP32はWifiも動くので

PC <- COM -> ESP32(Wifi AP) <- Wifi -> Android(Wifi)

という組み合わせも可能ですね(試してないけど)。Wifi版は既設のWifi環境に接続するかモバイルルータなどを使う必要がありましたがこの組み合わせにすると既設のWifiもモバイルルータも必要なし!スバラシイ

そんなわけでこれはちょっと急ぎで進めたいと思います。