Prototype ini hampir sejenis dengan mesin absensi sederhana yang pernah dibahas pada post sebelumnya. Karena adanya teknologi wireless serta konsep IoT yang mudah dan praktis diimplementasikan maka aplikasi menggunakan board nodeMCU bisa menjadi opsi. Nah untuk memudahkan dalam ujicoba, akan saya sediakan sample sistem informasi (berbasis web) yang dapat dimanfaatkan untuk coba-coba. Saya tidak akan menjelaskan secara rinci terkait pembuatan sistem infomasinya jadi harap maklum. Pastikan kalian sudah memahami/belajar tentang pembuatan aplikasi berbasis web sebagai dasarnya.
Konsep dari sistem absensi online dengan RFID kurang lebih akan seperti gambar diatas walaupun secara spesifik tidaklah sesimpel itu. Ini agak berbeda dari tutorial sebelumnya karena untuk memfasilitasi semua jenis kartu mifare classic (emoney, RFID tag, Sticker Tag) maka data yang akan diolah adalah uid saja (tidak ada proses write data). Reader RC522 akan membaca uid kemudian datanya diproses oleh NodeMCU untuk dikirim ke server (database). Nah dari proses pengiriman data ini, maka akan diperoleh response terkait dengan informasi dari uid hasil pembacaan (misal nama, status absensi, dll). Pengaturan informasi yang berkaitan dengan pengguna kartu dapat di atur dalam sistem informasi. Bagian yang paling penting adalah pembuatan Web API untuk menyediakan layanan penyimpanan data dan juga response. Biar lebih mudah dipahami, silahkan dipelajari tutorial pada post ini. Untuk mempermudah development maka percobaan dilakukan secara local. Pada dasarnya semua aplikasi yang dijalankan di localhost dapat di onlinekan dengan mengupload aplikasi tersebut ke hosting (lebih jelasnya dapat dipelajari sendiri). Ok langsung saja kita mulai proses pembuatan sistem Absensi menggunakan NodeMCU dan modul RFID RC522.
Alat dan Bahan
- NodeMCU
- RC522 - RFID module
- I2C OLED 128x64
- Buzzer
- Kabel-kabel Jumper
- Arduino IDE
- Notepad ++ (text editor)
- XAMPP (Saya pakai versi 7.4)
- Postman (web API testing)
Membuat Web API
CREATE DATABASE IF NOT EXISTS absensi; USE absensi; /*Table structure for table `data_absen` */ CREATE TABLE data_absen ( id int(100) NOT NULL AUTO_INCREMENT, tanggal date NOT NULL DEFAULT current_timestamp(), waktu time NOT NULL DEFAULT current_timestamp(), uid varchar(20) NOT NULL, status varchar(20) NOT NULL, PRIMARY KEY (id) ); /*Table structure for table `data_invalid` */ CREATE TABLE data_invalid ( id int(100) NOT NULL AUTO_INCREMENT, tanggal date NOT NULL DEFAULT current_timestamp(), waktu time NOT NULL DEFAULT current_timestamp(), uid varchar(10) NOT NULL, status varchar(10) NOT NULL, PRIMARY KEY (id) ); /*Table structure for table `data_karyawan` */ CREATE TABLE data_karyawan ( id int(50) NOT NULL AUTO_INCREMENT, created date NOT NULL DEFAULT current_timestamp(), uid varchar(20) NOT NULL, nama varchar(50) NOT NULL, division varchar(50) NOT NULL, mail varchar(50) NOT NULL, alamat text NOT NULL, picture varchar(100) NOT NULL, PRIMARY KEY (id) );
<?php class Database { private $host = "localhost"; private $database_name = "absensi"; private $username = "root"; private $password = ""; public $conn; public function getConnection(){ $this->conn = null; try{ $this->conn = new PDO("mysql:host=" . $this->host . ";dbname=" . $this->database_name, $this->username, $this->password); $this->conn->exec("set names utf8"); }catch(PDOException $exception){ echo "Database could not be connected: " . $exception->getMessage(); } return $this->conn; } } ?>
<?php date_default_timezone_set('Asia/Jakarta'); class Absensi{ // Connection private $conn; // Table private $db_table = "data_absen"; private $db_table1 = "data_karyawan"; private $db_table2 = "data_invalid"; // Columns public $id; public $tanggal; public $waktu; public $uid; public $status; public $last_status; public $nama; // Db connection public function __construct($db){ $this->conn = $db; } // CREATE public function createData(){ //1. Cek user $sqlQuery = "SELECT * FROM ". $this->db_table1 ." WHERE uid = :uid LIMIT 0,1"; $stmt = $this->conn->prepare($sqlQuery); $stmt->bindParam(":uid", $this->uid); $stmt->execute(); if($stmt->errorCode() == 0) { while(($dataRow = $stmt->fetch(PDO::FETCH_ASSOC)) != false) { $this->nama = $dataRow['nama']; } } else { $errors = $stmt->errorInfo(); echo($errors[2]); } $itemCount = $stmt->rowCount(); if($itemCount > 0){ //UID terdaftar -> cek status terakhir $sqlQuery = "SELECT data_absen.id, data_absen.uid, data_absen.status, data_karyawan.nama FROM ". $this->db_table .", ". $this->db_table1 ." WHERE data_absen.id = (SELECT MAX(data_absen.id) FROM ". $this->db_table ." WHERE data_absen.uid = :uid) AND data_karyawan.uid= :uid"; $stmt = $this->conn->prepare($sqlQuery); $stmt->bindParam(":uid", $this->uid); $stmt->execute(); $itemCount = $stmt->rowCount(); if($itemCount > 0){ //error handling if($stmt->errorCode() == 0) { while(($dataRow = $stmt->fetch(PDO::FETCH_ASSOC)) != false) { $this->last_status = $dataRow['status']; $this->nama = $dataRow['nama']; //echo($this->last_status); } } else { $errors = $stmt->errorInfo(); echo($errors[2]); } }else{ $this->last_status ="OUT"; } //set status if ($this->last_status == "IN"){ $this->status = "OUT"; }else{ $this->status= "IN"; } //Insert Data to data_absen $sqlQuery = "INSERT INTO ". $this->db_table ." SET waktu = :waktu, uid = :uid, status = :now_status"; $this->waktu = date("H:i:s"); $stmt = $this->conn->prepare($sqlQuery); // sanitize $this->uid=htmlspecialchars(strip_tags($this->uid)); // bind data $stmt->bindParam(":uid", $this->uid); $stmt->bindParam(":now_status", $this->status); $stmt->bindParam(":waktu", $this->waktu); if($stmt->execute()){ return true; } return false; } else{ //UID tidak terdaftar $this->status= "INVALID"; $this->nama ="Invalid"; //Insert Data to data_invalid $sqlQuery = "INSERT INTO ". $this->db_table2 ." SET waktu = :waktu, uid = :uid, status = :now_status"; $this->waktu = date("H:i:s"); $stmt = $this->conn->prepare($sqlQuery); // sanitize $this->uid=htmlspecialchars(strip_tags($this->uid)); // bind data $stmt->bindParam(":uid", $this->uid); $stmt->bindParam(":now_status", $this->status); $stmt->bindParam(":waktu", $this->waktu); if($stmt->execute()){ return true; } return false; } } } ?>
{ "waktu": "15:55:02", "nama": "Nama User", "uid": "B6B3C614", "status": "IN" }
<?php header("Access-Control-Allow-Origin: *"); header("Content-Type: application/json; charset=UTF-8"); include_once '../config/database.php'; include_once '../class/absensi.php'; $database = new Database(); $db = $database->getConnection(); $item = new Absensi($db); $item->uid = isset($_GET['uid']) ? $_GET['uid'] : die('wrong structure!'); if($item->createData()){ // create array $data_arr = array( "waktu" => $item->waktu, "nama" => $item->nama, "uid" => $item->uid, "status" => $item->status ); http_response_code(200); echo json_encode($data_arr); } else{ http_response_code(404); echo json_encode("Failed!"); } ?>
http://localhost/absensi/webapi/api/create.php?uid=YOUR_UID_TAG
Mesin Absensi NodeMCU + RC522
Wiring Diagram
Program NodeMCU
Let's test
Add some Custumization
Make it Online!
http://sissen.000webhostapp.com/webapi/api/create.php?uid=CARD_UID //[GET]Proses Absensi http://sissen.000webhostapp.com/webapi/api/get_last.php?uid=CARD_UID //[GET] Cek Tap kartu terakhir
24 Komentar
untuk rekap harian dan bulanan nya ada kah om? perlu untuk skripsi nih
BalasHapusbang, mau tanya, kalau port does not exist itu gmana cara troubleshooting nya? terimakasih banyak gan
BalasHapusini erorr message nya bang:
BalasHapusArduino: 1.8.13 (Windows 10), Board: "NodeMCU 0.9 (ESP-12 Module), 80 MHz, Flash, Legacy (new can return nullptr), All SSL ciphers (most compatible), 4MB (FS:2MB OTA:~1019KB), v2 Lower Memory, Disabled, None, Only Sketch, 115200"
Executable segment sizes:
IROM : 274956 - code in flash (default or ICACHE_FLASH_ATTR)
IRAM : 28284 / 32768 - code in IRAM (ICACHE_RAM_ATTR, ISRs...)
DATA : 1340 ) - initialized variables (global, static) in RAM/HEAP
RODATA : 1176 ) / 81920 - constants (global, static) in RAM/HEAP
BSS : 25576 ) - zeroed variables (global, static) in RAM/HEAP
Sketch uses 305756 bytes (29%) of program storage space. Maximum is 1044464 bytes.
Global variables use 28092 bytes (34%) of dynamic memory, leaving 53828 bytes for local variables. Maximum is 81920 bytes.
esptool.py v2.8
Serial port COM3
Connecting........_____....._____....._____....._____....._____....._____.....____Traceback (most recent call last):
File "C:\Users\User\AppData\Local\Arduino15\packages\esp8266\hardware\esp8266\2.7.4/tools/upload.py", line 65, in
esptool.main(cmdline)
File "C:/Users/User/AppData/Local/Arduino15/packages/esp8266/hardware/esp8266/2.7.4/tools/esptool\esptool.py", line 2890, in main
esp.connect(args.before)
File "C:/Users/User/AppData/Local/Arduino15/packages/esp8266/hardware/esp8266/2.7.4/tools/esptool\esptool.py", line 483, in connect
raise FatalError('Failed to connect to %s: %s' % (self.CHIP_NAME, last_error))
esptool.FatalError: Failed to connect to ESP8266: Timed out waiting for packet header
_
the selected serial port _
does not exist or your board is not connected
This report would have more information with
"Show verbose output during compilation"
option enabled in File -> Preferences.
Bang kasus nya sama kaya saya? benerin nya gimana ya bang?
Hapussekarang erorr gini bang
BalasHapusexit status 1
call to 'HTTPClient::begin' declared with attribute error: obsolete API, use ::begin(WiFiClient, url)
pastikan library yang digunakan memiliki versi yang sama dengan yang ada di tutorial ya.. klo beda tinggal pilih di select version
Hapussudah saya sesuaikan, tapi masih seperti itu
HapusCoba di cek pada alamat API nya gan .. sesuaikan dengan struktur api yang agan buat.
Hapusatau dapat dicoba saja via sissen.000webhostapp.com . sesuai instruksi diatas
mohon infonya bang, untuk tutorial cruddiy ada ngga , sama file dashboarnya error dibuka
BalasHapuslangsung dr si empunya saja gan .. https://github.com/jan-vandenberg/cruddiy
Hapuserrornya gmn gan?
maaf bang mau tanya kok pas saya tap kartunya malah dapet eror gini ya? Response: deserializeJson() failed: IncompleteInput
BalasHapusmohon bantuannya bang terimakasih
kemungkinan ada masalah di arduinojsonnya gan.. pastikan librarynya memakai versi yg sama kayak diatas
Hapusudah sama tapi masih eror sama kaya yang diatas deserializeJson() failed: IncompleteInput kenapa ya?
Hapuskalau disaya ternyata servernya tidak merespon, jd pas saya coba buat hosting dan pakai server hosting itu malahan bisa
Hapustrim dah konfirmasi gan... semoga bermanfaat
Hapusbang, kalo mau nambahin biar kartu rfid ada expired nya gmna yg bang, makasih bang
BalasHapusmunkin perlu diubah untuk mekanisme statusnya gan .. misal, valid, invalid, expired .. dll
Hapussilahkan berkreasi
Bang kalau ntag 215 support ga reader yg ini?
BalasHapuswah .. kurang paham gan .. ane gak ada kartu jenis ntag jd gak bs nyobain..
Hapusbang mau tanya buat daftarin nya liat id nya gmana?
BalasHapusdi invalid gan.. ntr di pilih aja tombol +
Hapuskalo buat rangkaian nya bikin pake apa bang?
Hapusbebas gan.. pake pcb titik/bolong jg bisa.. tinggal di hubung2 kan sesuai wiring diagramny
HapusApakah ini hanya untuk absensi saja , apakah memang tidak bisa untuk mendaftarkan karyawan melaui taping
BalasHapus