arrow-righthamburgerlogo-marksocial-facebooksocial-githubsocial-twitter
2018.07.05

NefryBTとキーボードで作る簡易勤怠管理システム

のびすけ

オフィスなう。
   このエントリーをはてなブックマークに追加  

こんにちは、代表のn0bisukeです。

今日はとある電子工作向けキーパッドを手に入れたので、Nefry BTで簡易的な勤怠管理システムを作ってみました。ちなみにオチとかないです。

使うもの

マトリックスフィルムボタンキーボード メンブレン式キーボード 4*4

HiLetgoというストアから出品されています。眺めていて使ってみたいなぁという欲求が湧いたのでポチりました。

ちなみに5個セットなので、あと4個なにか作れます。

Arduino Unoで動かしてみる

AmazonのページにはArduino対応と書いているのでどうやら使えるらしい。

ESP8266: Interfacing with a 4×4 Matrix Keypad という記事があったので参考にArduinoで動かしてみました。

配線

Arduino Unoとあとで紹介するNefry BTでの配線はこんな感じです。

プログラム

こちらのライブラリをインストールしましょう。

ライブラリマネージャからもインストールできます。

#include <Keypad.h>

const byte n_rows = 4;
const byte n_cols = 4;

char keys[n_rows][n_cols] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte colPins[n_rows] = {3, 2, 1, 0};
byte rowPins[n_cols] = {7, 6, 5, 4};

Keypad myKeypad = Keypad( makeKeymap(keys), rowPins, colPins, n_rows, n_cols);

void setup(){
  Serial.begin(115200);
}

void loop(){
  char myKey = myKeypad.getKey();

  if (myKey != NULL){
    Serial.print("Key pressed: ");
    Serial.println(myKey);
  }
}

実行

電子工作用のキーボード使ってみたけどハマることなく試せた 勤怠記録とかオフィスハックの何かに使いたい #dotstudio

n0bisukeさん(@n0bisuke)がシェアした投稿 -

Nefry BTで動作させて勤怠システムに

出退勤の記録を付ける電子工作は、今まで何度か作りはしたものの導入まで至っていなかったです。

作り込もうとして力を入れすぎて力尽きる問題が大きいと思っています。

ということで実装がシンプルな勤怠システムをとりあえず導入してみました。

ボタン入力式

仕様は数字を押して選択し、Aボタンで出勤記録、Bボタンで退勤記録です。

ディスプレイには登録している名前が出ます。

多分そのうちSuica連携とかBLEデバイス連携とか指紋とか声門とかそういうのも試してみる気はするのですが、 ボタン入力とHTTP通信だけの実装のシンプルさがとりあえず始めるには重要な気がしました。

制作時間1時間程度。HTTP POST周りで少し手こずってました。

Nefryとつないでみた。キーの押し心地がよい

n0bisukeさん(@n0bisuke)がシェアした投稿 -

実装

Nefry BTでのHTTP POSTも合わせて読むとコード理解が進みます。

#include <Keypad.h>
#include <NefryDisplay.h>
#include <WiFiClientSecure.h>
WiFiClientSecure client;

String StrPerEncord(const char* c_str);
String escapeParameter(String param);
void hipchatPost(String message);

const int HTTP_PORT = 443;
const char* HOST = "xxxxxxxxxx.hipchat.com";

const byte n_rows = 4;
const byte n_cols = 4;

char keys[n_rows][n_cols] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};

byte colPins[n_rows] = {D3, D2, D1, D0};
byte rowPins[n_cols] = {D7, D6, D5, D4};
Keypad myKeypad = Keypad( makeKeymap(keys), rowPins, colPins, n_rows, n_cols);

String storeMessage = "";

//3行目だけにPrint
void nfDisplay3Print(String mes){
  NefryDisplay.print("");
  NefryDisplay.print("");
  NefryDisplay.print(mes);
}

void setup() {
  Serial.begin(115200);
  NefryDisplay.setTitle("KINTAI");
  nfDisplay3Print("Please Input...");
}

void loop() {
  char myKey = myKeypad.getKey();
  String member = "";

  //ボタンが押された時の処理
  if (myKey != NULL){
    Serial.print("Key pressed: ");
    Serial.println(myKey);

    if(String(myKey) == "1"){
      member += "n0bisuke";
      storeMessage = member;
    }else if(String(myKey) == "2"){
      member += "chantoku";
      storeMessage = member;
    }else if(String(myKey) == "3"){
      member += "kiki";
      storeMessage = member;
    }else if(String(myKey) == "4"){
      member += "takudon";
      storeMessage = member;
    }else if(String(myKey) == "5"){
      member += "sasakitomohiro";
      storeMessage = member;
    }

    nfDisplay3Print(String(myKey) + ":" + member);

    if(String(myKey) == "A"){
      nfDisplay3Print(String(myKey) + ": [Office IN] post to HipChat...");

      storeMessage += "さんが出勤しました。";
      hipchatPost(storeMessage); //HipChatに投稿
      storeMessage = ""; //リセット

      nfDisplay3Print(String(myKey) + ": POST DONE");
    }else if(String(myKey) == "B"){
      nfDisplay3Print(String(myKey) + ": [Office OUT] post to HipChat...");

      storeMessage += "さんが退勤しました。";
      hipchatPost(storeMessage); //HipChatに投稿
      storeMessage = ""; //リセット

      nfDisplay3Print(String(myKey) + ": POST DONE");
    }  
  }
}

void hipchatPost(String message){
  String url = "/v2/room/4651875/notification?auth_token=xxxxxxxxxxxxxxxx";
  url += "&color=green&notify=false&message_format=text&message=";
  url += StrPerEncord(escapeParameter(message + " (yey)").c_str());

  Serial.print("connecting to ");
  Serial.println(HOST);

  if (!client.connect(HOST, HTTP_PORT)) {
    Serial.println("connection failed");
    return;
  }

  client.println("POST " + url + " HTTP/1.1");
  client.println("Content-Type: application/json");
  client.println("Content-Type: application/x-www-form-urlencoded");
  client.println("Host: " + String(HOST));
  client.println("Connection: close");
  client.println();

  unsigned long timeout = millis();
  while (client.available() == 0) {    
    if (millis() - timeout > 5000) {
        Serial.println(">>> Client Timeout !");
        client.stop();
        return;
    }
  }

  // Read all the lines of the reply from server and print them to Serial
  while(client.available()) {
      String line = client.readStringUntil('\r');
      Serial.print(line);
  }

  Serial.println();
  Serial.println("closing connection");
}

String StrPerEncord(const char* c_str) {
  uint16_t i = 0;
  String str_ret = "";
  char c1[3], c2[3], c3[3];

  while (c_str[i] != '\0') {
    if (c_str[i] >= 0xC2 && c_str[i] <= 0xD1) { //2バイト文字
      sprintf(c1, "%2x", c_str[i]);
      sprintf(c2, "%2x", c_str[i + 1]);
      str_ret += "%" + String(c1) + "%" + String(c2);
      i = i + 2;
    } else if (c_str[i] >= 0xE2 && c_str[i] <= 0xEF) {
      sprintf(c1, "%2x", c_str[i]);
      sprintf(c2, "%2x", c_str[i + 1]);
      sprintf(c3, "%2x", c_str[i + 2]);
      str_ret += "%" + String(c1) + "%" + String(c2) + "%" + String(c3);
      i = i + 3;
    } else {
      str_ret += String(c_str[i]);
      i++;
    }
  }
  return str_ret;
}

String escapeParameter(String param) {
  param.replace("%", "%25");
  param.replace("+", "%2B");
  param.replace(" ", "+");
  param.replace("\"", "%22");
  param.replace("#", "%23");
  param.replace("$", "%24");
  param.replace("&", "%26");
  param.replace("'", "%27");
  param.replace("(", "%28");
  param.replace(")", "%29");
  param.replace("*", "%2A");
  param.replace(",", "%2C");
  param.replace("/", "%2F");
  param.replace(":", "%3A");
  param.replace(";", "%3B");
  param.replace("<", "%3C");
  param.replace("=", "%3D");
  param.replace(">", "%3E");
  param.replace("?", "%3F");
  param.replace("@", "%40");
  param.replace("[", "%5B");
  param.replace("\\", "%5C");
  param.replace("]", "%5D");
  param.replace("^", "%5E");
  param.replace("'", "%60");
  param.replace("{", "%7B");
  param.replace("|", "%7C");
  param.replace("}", "%7D");
  return param;
}

まとめ

運用1日目ですが問題ないです(謎)

実際にはシートに記録したりした方が良いと思いますが今後検討です!

HipChatの部分はうちの社内がHipChatだからというだけですが、LINEだったりSlackだったりも同様のやり方で連携できます。

思ったより簡単に試せたなぁという印象なのでみなさんもぜひ試してみてください。

   このエントリーをはてなブックマークに追加