Project

rbzk

0.0
The project is in a healthy, maintained state
A Ruby implementation of the ZK protocol for fingerprint and biometric attendance devices
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
 Dependencies

Development

~> 2.0
~> 13.0
~> 3.0

Runtime

~> 0.1
~> 1.2
 Project Readme

RBZK

A Ruby implementation of the ZK protocol for fingerprint and biometric attendance devices.

This project is inspired by and based on the pyzk Python library, adapting its protocol implementation to Ruby while maintaining compatibility with ZKTeco devices.

Installation

Add this line to your application's Gemfile:

gem 'rbzk'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install rbzk

Library Usage

The rbzk gem provides a RBZK::ZK class to interact with ZKTeco devices.

Basic Connection

require 'rbzk'

# Create a new ZK instance
# Replace with your device's IP address
zk = RBZK::ZK.new('192.168.1.201', port: 4370, timeout: 60, password: 0)

# Connect to the device
begin
  conn = zk.connect

  # Check if connected successfully
  if conn.connected?
    puts "Connected successfully!"
  else
    puts "Connection failed!"
    exit 1
  end

  # Disable the device to ensure exclusive access for sensitive operations
  puts 'Disabling device...'
  conn.disable_device

  # --- Your operations here ---
  puts "Device Firmware Version: #{conn.get_firmware_version}"
  puts "Serial Number: #{conn.get_serialnumber}"
  # --- End of operations ---

  # Re-enable the device when done
  puts 'Enabling device...'
  conn.enable_device
rescue RBZK::ZKError => e # Catch specific RBZK errors
  puts "ZK Error: #{e.message}"
rescue => e # Catch other potential errors
  puts "Generic Error: #{e.message}"
ensure
  # Always disconnect when done
  conn.disconnect if conn && conn.connected?
  puts "Disconnected."
end

Device Information

# Assuming 'conn' is an active and connected RBZK::ZK instance
# (See Basic Connection example)

puts "--- Device Information ---"
puts "Firmware Version: #{conn.get_firmware_version}"
puts "Serial Number: #{conn.get_serialnumber}"
puts "MAC Address: #{conn.get_mac}"
puts "Device Name: #{conn.get_device_name}"
puts "Platform: #{conn.get_platform}"
puts "Fingerprint Algorithm Version: #{conn.get_fp_version}"
# puts "Face Algorithm Version: #{conn.get_face_version}" # If applicable
puts "Device Time: #{conn.get_time}"

# Get user, fingerprint, and record counts/capacities
conn.read_sizes # Updates internal counts
puts "User Count: #{conn.instance_variable_get(:@users)}"
puts "Fingerprint Count: #{conn.instance_variable_get(:@fingers)}"
puts "Attendance Record Count: #{conn.instance_variable_get(:@records)}"
puts "User Capacity: #{conn.instance_variable_get(:@users_cap)}"
puts "Fingerprint Capacity: #{conn.instance_variable_get(:@fingers_cap)}"
puts "Record Capacity: #{conn.instance_variable_get(:@rec_cap)}"

Device Control

# Assuming 'conn' is an active and connected RBZK::ZK instance

# Restart the device
# conn.restart
# puts "Device restarting..."

# Power off the device (use with caution)
# conn.poweroff
# puts "Device powering off..."

# Test a voice prompt (e.g., "Thank you")
# conn.test_voice(RBZK::Constants::EF_THANKYOU) # Check Constants for available voice enums
# puts "Tested voice prompt."

# Unlock the door for 5 seconds
conn.unlock(5)
puts "Door unlocked for 5 seconds."

# Get door lock state
state = conn.get_lock_state
puts "Door is #{state ? 'Open' : 'Closed'}."

LCD Operations

# Assuming 'conn' is an active and connected RBZK::ZK instance

# Write text to LCD (line number, text)
conn.write_lcd(1, "Hello from RBZK!")
puts "Text written to LCD line 1."
conn.write_lcd(2, Time.now.strftime("%H:%M:%S"))
puts "Text written to LCD line 2."

# Clear the LCD display
# sleep 5 # Keep text for 5 seconds
# conn.clear_lcd
# puts "LCD cleared."

User Management

Getting Users

# Assuming 'conn' is an active and connected RBZK::ZK instance

puts '--- Get Users ---'
users = conn.get_users
users.each do |user|
  privilege = 'User'
  privilege = 'Admin' if user.privilege == RBZK::Constants::USER_ADMIN

  puts "UID: #{user.uid}"
  puts "Name: #{user.name}"
  puts "Privilege: #{privilege}"
  puts "Password: #{user.password}" # Be mindful of displaying passwords
  puts "Group ID: #{user.group_id}"
  puts "User ID (PIN2): #{user.user_id}"
  puts "Card: #{user.card}"
  puts "---"
end

Add/Update User

# Assuming 'conn' is an active and connected RBZK::ZK instance

puts '--- Add/Update User ---'
# For a new user, UID can often be omitted if the device assigns it.
# To update an existing user, provide their UID.
# conn.read_sizes # Ensure @next_uid is populated if device assigns UIDs
# new_uid = conn.instance_variable_get(:@next_uid) # Example for new user

user_attributes = {
  uid: 123, # Specify UID to update, or omit for device to assign (check device behavior)
  name: 'John Doe',
  privilege: RBZK::Constants::USER_DEFAULT,
  password: '1234',
  group_id: '1',
  user_id: 'JD123', # Custom User ID / PIN2
  card: 7890
}

if conn.set_user(**user_attributes)
  puts "User #{user_attributes[:name]} (UID: #{user_attributes[:uid] || 'auto'}) added/updated successfully."
  conn.refresh_data # Good practice to refresh data after modifications
else
  puts "Failed to add/update user."
end

Delete User

# Assuming 'conn' is an active and connected RBZK::ZK instance

puts '--- Delete User ---'
uid_to_delete = 123 # UID of the user to delete

if conn.delete_user(uid: uid_to_delete)
  puts "User with UID #{uid_to_delete} deleted successfully."
  conn.refresh_data
else
  puts "Failed to delete user with UID #{uid_to_delete} (may not exist)."
end

Attendance Log Management

Getting Attendance Logs

# Assuming 'conn' is an active and connected RBZK::ZK instance

puts '--- Get Attendance Logs ---'
logs = conn.get_attendance_logs
if logs.empty?
  puts "No attendance logs found."
else
  logs.each_with_index do |log, index|
    puts "Log ##{index + 1}:"
    puts "  Device UID: #{log.uid}" # Internal device UID for the record
    puts "  User ID (PIN2): #{log.user_id}"
    # Status: Check-in, Check-out, etc. (Refer to ZK documentation for specific status codes)
    puts "  Status: #{log.status}"
    # Punch: Fingerprint, Password, Card, etc. (Refer to ZK documentation)
    puts "  Punch Type: #{log.punch}"
    puts "  Timestamp: #{log.timestamp.strftime('%Y-%m-%d %H:%M:%S')}"
    puts "---"
  end
end

Clear Attendance Logs

# Assuming 'conn' is an active and connected RBZK::ZK instance

# puts '--- Clear Attendance Logs ---'
# puts "WARNING: This will delete all attendance logs from the device."
# print "Are you sure? (yes/N): "
# confirmation = gets.chomp
# if confirmation.downcase == 'yes'
#   if conn.clear_attendance
#     puts "Attendance logs cleared successfully."
#     conn.refresh_data
#   else
#     puts "Failed to clear attendance logs."
#   end
# else
#   puts "Operation cancelled."
# end

Fingerprint Template Management

(Note: Fingerprint template data is binary and device-specific. Handling it requires careful understanding of the ZK protocol and template formats.)

Get All Fingerprint Templates

# Assuming 'conn' is an active and connected RBZK::ZK instance

puts '--- Get All Fingerprint Templates ---'
templates = conn.get_templates
if templates.empty?
  puts "No fingerprint templates found."
else
  templates.each do |fp_template|
    puts "UID: #{fp_template.uid}, Finger ID: #{fp_template.fid}, Valid: #{fp_template.valid}, Size: #{fp_template.size}"
  end
end

Get a Specific User's Fingerprint Template

# Assuming 'conn' is an active and connected RBZK::ZK instance

user_uid = '123' # The user's main UID (often a string from device)
finger_id = 0    # Finger index (0-9)

begin
  fp_template = conn.get_user_template(user_uid, finger_id)
  if fp_template
    puts "Template for UID #{user_uid}, Finger ID #{finger_id}: Size #{fp_template.size}, Valid: #{fp_template.valid}"
    # fp_template.template contains the binary data
  else
    puts "Template not found for UID #{user_uid}, Finger ID #{finger_id}."
  end
rescue RBZK::ZKErrorResponse => e
  puts "Error getting template: #{e.message}"
end

Set a User's Fingerprint Template

(This is an advanced operation. You need valid template data.)

# Assuming 'conn' is an active and connected RBZK::ZK instance
# And `valid_template_data` is a binary string of a valid fingerprint template

# user_uid = '123'
# finger_id = 0
# valid_flag = 1 # 1 for valid, 0 for invalid/duplicate
# valid_template_data = "BINARY_TEMPLATE_DATA_HERE" # Replace with actual binary data

# begin
#   if conn.set_user_template(valid_template_data, user_uid, finger_id, valid_flag)
#     puts "Fingerprint template set successfully for UID #{user_uid}, Finger ID #{finger_id}."
#     conn.refresh_data
#   else
#     puts "Failed to set fingerprint template."
#   end
# rescue RBZK::ZKErrorResponse => e
#   puts "Error setting template: #{e.message}"
# end

Delete/Clear Fingerprint Templates

# Assuming 'conn' is an active and connected RBZK::ZK instance

# Delete a specific fingerprint for a user
# user_uid_for_fp_delete = '123'
# finger_id_to_delete = 0
# if conn.delete_user_template(user_uid_for_fp_delete, finger_id_to_delete)
#   puts "Template for UID #{user_uid_for_fp_delete}, FID #{finger_id_to_delete} deleted."
#   conn.refresh_data
# else
#   puts "Failed to delete template."
# end

# Clear all fingerprint templates for a specific user
# user_uid_to_clear_fps = '123'
# if conn.clear_user_template(user_uid_to_clear_fps) # Method name might vary, e.g., delete_user_fingerprints
#   puts "All templates for UID #{user_uid_to_clear_fps} cleared."
#   conn.refresh_data
# else
#   puts "Failed to clear user templates."
# end

# Clear ALL fingerprint templates on the device (Use with extreme caution!)
# puts "WARNING: This will delete ALL fingerprint templates from the device."
# print "Are you sure? (yes/N): "
# confirmation_clear_all_fp = gets.chomp
# if confirmation_clear_all_fp.downcase == 'yes'
#   if conn.clear_templates # Or clear_fingerprints
#     puts "All fingerprint templates cleared from device."
#     conn.refresh_data
#   else
#     puts "Failed to clear all fingerprint templates."
#   end
# else
#   puts "Operation cancelled."
# end

Device Time

# Assuming 'conn' is an active and connected RBZK::ZK instance

# Get device time
current_device_time = conn.get_time
puts "Current device time: #{current_device_time}"

# Set device time (to current system time)
# new_time = Time.now
# if conn.set_time(new_time)
#   puts "Device time set to #{new_time} successfully."
# else
#   puts "Failed to set device time."
# end

Command Line Interface (CLI)

The rbzk gem also provides a command-line tool named rbzk for quick interactions with your ZKTeco devices.

Global Options

These options can be used with most commands:

  • --ip <IP_ADDRESS>: IP address of the device.
  • --port <PORT>: Port number (default: 4370).
  • --timeout <SECONDS>: Connection timeout in seconds (default: 30 or 60).
  • --password <PASSWORD>: Device communication password (default: 0).
  • --verbose: Enable verbose output.
  • --force-udp: Force UDP mode for communication.
  • --no-ping: Skip the initial ping check.
  • --encoding <ENCODING>: String encoding (default: UTF-8).

Available Commands

Here are some of the primary commands available:

  • rbzk info [--ip IP]: Get detailed device information.
  • rbzk refresh [--ip IP]: Refresh the device's internal data (useful after making changes).
  • rbzk users [--ip IP]: List all users on the device.
  • rbzk logs [--ip IP] [options]: Get attendance logs.
    • --today: Get today's logs.
    • --yesterday: Get yesterday's logs.
    • --week: Get logs for the current week.
    • --month: Get logs for the current month.
    • --start-date YYYY-MM-DD: Filter logs from a specific start date.
    • --end-date YYYY-MM-DD: Filter logs up to a specific end date.
    • --limit N: Limit the number of logs displayed (0 for all).
    • Aliases: rbzk logs-today, rbzk logs-yesterday, rbzk logs-week, rbzk logs-month.
  • rbzk logs-all [--ip IP]: Get all attendance logs without any limit.
  • rbzk logs-custom <START_DATE> <END_DATE> [--ip IP]: Get logs for a custom date range (YYYY-MM-DD).
  • rbzk clear-logs [--ip IP]: Clear all attendance logs from the device (prompts for confirmation).
  • rbzk unlock [--ip IP] [--time SECONDS]: Unlock the connected door (default 3 seconds).
  • rbzk door-state [--ip IP]: Get the current state of the door lock (Open/Closed).
  • rbzk write-lcd <LINE_NUMBER> <TEXT> [--ip IP]: Write text to the device's LCD screen.
  • rbzk clear-lcd [--ip IP]: Clear the device's LCD screen.
  • rbzk add-user [--ip IP] [options]: Add or update a user.
    • `--uid <UID