zklib 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,37 @@
1
+ class Zklib
2
+ module DataManagement
3
+ # Free data for transmission
4
+ def free_data
5
+ execute_cmd(
6
+ command: CMD_FREE_DATA,
7
+ command_string: ''
8
+ ) do |opts|
9
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
10
+
11
+ data = opts[:data]
12
+ if data.length > 7
13
+ data.split("\u0000").pop
14
+ else
15
+ puts 'ERROR: Invalid free data response'
16
+ end
17
+ end
18
+ end
19
+
20
+ # Refresh data for transmission
21
+ def refresh_data
22
+ execute_cmd(
23
+ command: CMD_REFRESHDATA,
24
+ command_string: ''
25
+ ) do |opts|
26
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
27
+
28
+ data = opts[:data]
29
+ if data.length > 7
30
+ data.split("\u0000").pop
31
+ else
32
+ puts 'ERROR: Invalid refresh data response'
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,91 @@
1
+ class Zklib
2
+ module DeviceManagement
3
+ DEVICE_NAME_KEYWORD = '~DeviceName'
4
+ DISABLE_DEVICE_KEYWORD = "\u0000\u0000"
5
+
6
+ # Disable attendance machine
7
+ def disable_device
8
+ execute_cmd(
9
+ command: CMD_DISABLEDEVICE,
10
+ command_string: DISABLE_DEVICE_KEYWORD
11
+ ) do |opts|
12
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
13
+
14
+ data = opts[:data]
15
+ if data.length > 7
16
+ data.split("\u0000").pop
17
+ else
18
+ puts 'ERROR: Invalid disable device response'
19
+ end
20
+ end
21
+ end
22
+
23
+ # Enable attendance machine
24
+ def enable_device
25
+ execute_cmd(
26
+ command: CMD_ENABLEDEVICE,
27
+ command_string: ''
28
+ ) do |opts|
29
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
30
+
31
+ data = opts[:data]
32
+ if data.length > 7
33
+ data.split("\u0000").pop
34
+ else
35
+ puts 'ERROR: Invalid enable device response'
36
+ end
37
+ end
38
+ end
39
+
40
+ # Get device name
41
+ def get_device_name
42
+ execute_cmd(
43
+ command: CMD_DEVICE,
44
+ command_string: DEVICE_NAME_KEYWORD
45
+ ) do |opts|
46
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
47
+
48
+ data = opts[:data]
49
+ if data.length > 8
50
+ data.split("\u0000").pop.tr("#{DEVICE_NAME_KEYWORD}=", '')
51
+ else
52
+ puts 'ERROR: Invalid device name response'
53
+ end
54
+ end
55
+ end
56
+
57
+ # Turn off attendance machine
58
+ def power_off_device
59
+ execute_cmd(
60
+ command: CMD_POWEROFF,
61
+ command_string: ''
62
+ ) do |opts|
63
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
64
+
65
+ data = opts[:data]
66
+ if data.length > 7
67
+ data.split("\u0000").pop
68
+ else
69
+ puts 'ERROR: Invalid power off device response'
70
+ end
71
+ end
72
+ end
73
+
74
+ # Restart attendance machine
75
+ def restart_device
76
+ execute_cmd(
77
+ command: CMD_RESTART,
78
+ command_string: ''
79
+ ) do |opts|
80
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
81
+
82
+ data = opts[:data]
83
+ if data.length > 7
84
+ data.split("\u0000").pop
85
+ else
86
+ puts 'ERROR: Invalid restart device response'
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,40 @@
1
+ class Zklib
2
+ module FaceManagement
3
+ TURN_FACE_OFF_KEYWORD = 'FaceFunOff'
4
+ TURN_FACE_ON_KEYWORD = 'FaceFunOn'
5
+
6
+ # Turn face off
7
+ def turn_face_off
8
+ execute_cmd(
9
+ command: CMD_DEVICE,
10
+ command_string: TURN_FACE_OFF_KEYWORD
11
+ ) do |opts|
12
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
13
+
14
+ data = opts[:data]
15
+ if data.length > 7
16
+ data.split("\u0000").pop
17
+ else
18
+ puts 'ERROR: Invalid turn face off response'
19
+ end
20
+ end
21
+ end
22
+
23
+ # Turn face on
24
+ def turn_face_on
25
+ execute_cmd(
26
+ command: CMD_DEVICE,
27
+ command_string: TURN_FACE_ON_KEYWORD
28
+ ) do |opts|
29
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
30
+
31
+ data = opts[:data]
32
+ if data.length > 7
33
+ data.split("\u0000").pop
34
+ else
35
+ puts 'ERROR: Invalid turn face on response'
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,181 @@
1
+ class Zklib
2
+ module Helper
3
+ # Check validity of response
4
+ #
5
+ # param options
6
+ # |_ data Data to check validity
7
+ def check_valid(options)
8
+ BinData::Uint16le.read(options[:data][0..-1]).snapshot == CMD_ACK_OK
9
+ end
10
+
11
+ # Create checksum for execution
12
+ #
13
+ # param options
14
+ # |_ data Data to create checksum
15
+ def create_checksum(options)
16
+ data = options[:data]
17
+ checksum = 0
18
+
19
+ (0...data.length).step(2) do |i|
20
+ checksum += (i == data.length - 1) ?
21
+ BinData::Uint8le.read(data[i]).snapshot :
22
+ BinData::Uint16le.read(data[i..-1]).snapshot
23
+ checksum %= USHRT_MAX
24
+ end
25
+
26
+ chksum = USHRT_MAX - checksum - 1
27
+ chksum
28
+ end
29
+
30
+ # Create header for execution
31
+ #
32
+ # param options
33
+ # |_ command Command value
34
+ # |_ checksum Checksum
35
+ # |_ session_id Session ID
36
+ # |_ reply_id Reply ID
37
+ # |_ command_string Command string
38
+ def create_header(options)
39
+ header_buffer = StringIO.new
40
+ binary_writer = BinData::Uint16le.new
41
+
42
+ # Write command header
43
+ binary_writer.value = options[:command]
44
+ header_buffer.pos = 0
45
+ binary_writer.write(header_buffer)
46
+
47
+ # Write checksum header
48
+ binary_writer.value = options[:checksum]
49
+ header_buffer.pos = 2
50
+ binary_writer.write(header_buffer)
51
+
52
+ # Write session ID header
53
+ binary_writer.value = options[:session_id]
54
+ header_buffer.pos = 4
55
+ binary_writer.write(header_buffer)
56
+
57
+ # Write reply ID header
58
+ binary_writer.value = options[:reply_id]
59
+ header_buffer.pos = 6
60
+ binary_writer.write(header_buffer)
61
+
62
+ # Write command string header
63
+ header_buffer.pos = 8
64
+ header_buffer.write(options[:command_string])
65
+
66
+ # Rewrite checksum header
67
+ binary_writer.value = create_checksum(data: header_buffer.string)
68
+ header_buffer.pos = 2
69
+ binary_writer.write(header_buffer)
70
+
71
+ # Rewrite reply ID header
72
+ binary_writer.value = (options[:reply_id] + 1) % USHRT_MAX
73
+ header_buffer.pos = 6
74
+ binary_writer.write(header_buffer)
75
+
76
+ header_buffer.string
77
+ end
78
+
79
+ # Convert number of seconds to time
80
+ #
81
+ # param options
82
+ # |_ seconds Time in seconds to decode
83
+ def decode_time(options)
84
+ time = options[:seconds]
85
+
86
+ # Calculate second value
87
+ second = time % 60
88
+ time = (time - second) / 60
89
+
90
+ # Calculate minute value
91
+ minute = time % 60
92
+ time = (time - minute) / 60
93
+
94
+ # Calculate hour value
95
+ hour = time % 24
96
+ time = (time - hour) / 24
97
+
98
+ # Calculate day value
99
+ day = time % 31 + 1
100
+ time = (time - day + 1) / 31
101
+
102
+ # Calculate month value
103
+ month = time % 12 + 1
104
+ time = (time - month + 1) / 12
105
+
106
+ # Calculate year value
107
+ year = time + 2000
108
+
109
+ Time.new(year, month, day, hour, minute, second)
110
+ end
111
+
112
+ def decode_user_data(options)
113
+ data = options[:data]
114
+
115
+ {
116
+ uid: BinData::Uint16be.read(data[0..1]).snapshot,
117
+ role: BinData::Uint16le.read(data[2..3]).snapshot,
118
+ password: nil,
119
+ name: nil,
120
+ cardno: nil,
121
+ userid: nil
122
+ }
123
+ end
124
+
125
+ # Convert time to number of seconds
126
+ #
127
+ # param options
128
+ # |_ time Time object to encode
129
+ def encode_time(options)
130
+ time = options[:time]
131
+
132
+ ((time.year % 100) * 12 * 31 + ((time.mon - 1) * 31) + time.day - 1) * (24 * 60 * 60) + (time.hour * 60 + time.min) * 60 + time.sec
133
+ end
134
+
135
+ # Execute command on attendance machine
136
+ #
137
+ # param options
138
+ # |_ command Command to execute
139
+ # |_ command_string Command string
140
+ def execute_cmd(options)
141
+ command = options[:command]
142
+ self.reply_id = USHRT_MAX - 1 if command == CMD_CONNECT
143
+ header = create_header(
144
+ command: command,
145
+ checksum: 0,
146
+ session_id: session_id,
147
+ reply_id: reply_id,
148
+ command_string: options[:command_string]
149
+ )
150
+
151
+ # Send command
152
+ socket = UDPSocket.new
153
+ socket.bind('0.0.0.0', inport)
154
+ socket.send(header, 0, ip, port)
155
+ self.data_recv = socket.recvfrom(USHRT_MAX)[0] if IO.select([socket], nil, nil, 10)
156
+ socket.close
157
+
158
+ # Callback
159
+ if data_recv && data_recv.length > 0
160
+ self.session_id = BinData::Uint16le.read(data_recv[4..-1]).snapshot
161
+ self.reply_id = BinData::Uint16le.read(data_recv[6..-1]).snapshot
162
+
163
+ yield(valid: true, data: data_recv) if block_given?
164
+ else
165
+ yield(valid: false, error: 'Empty response') if block_given?
166
+ end
167
+ end
168
+
169
+ # Receive data from non-blocking socket
170
+ #
171
+ # param options
172
+ # |_ socket Socket to receive data from
173
+ def receive_nonblock(options)
174
+ return options[:socket].recvfrom_nonblock(USHRT_MAX)
175
+ rescue IO::WaitReadable
176
+ IO.select([options[:socket]])
177
+
178
+ retry
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,22 @@
1
+ class Zklib
2
+ module PINManagement
3
+ PIN_WIDTH_KEYWORD = '~PIN2Width'
4
+
5
+ # Get PIN width
6
+ def get_pin_width
7
+ execute_cmd(
8
+ command: CMD_DEVICE,
9
+ command_string: PIN_WIDTH_KEYWORD
10
+ ) do |opts|
11
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
12
+
13
+ data = opts[:data]
14
+ if data.length > 8
15
+ data.split("\u0000").pop.tr("#{PIN_WIDTH_KEYWORD}=", '')
16
+ else
17
+ puts 'ERROR: Invalid PIN width response'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ class Zklib
2
+ module PlatformManagement
3
+ PLATFORM_KEYWORD = '~Platform'
4
+
5
+ # Get platform
6
+ def get_platform
7
+ execute_cmd(
8
+ command: CMD_DEVICE,
9
+ command_string: PLATFORM_KEYWORD
10
+ ) do |opts|
11
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
12
+
13
+ data = opts[:data]
14
+ if data.length > 8
15
+ data.split("\u0000").pop.tr("#{PLATFORM_KEYWORD}=", '')
16
+ else
17
+ puts 'ERROR: Invalid platform response'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ class Zklib
2
+ module SerialManagement
3
+ SERIAL_KEYWORD = '~SerialNumber'
4
+
5
+ # Get serial number of attendance machine
6
+ def get_serial_number
7
+ execute_cmd(
8
+ command: CMD_DEVICE,
9
+ command_string: SERIAL_KEYWORD
10
+ ) do |opts|
11
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
12
+
13
+ data = opts[:data]
14
+ if data.length > 8
15
+ data.split("\u0000").pop.tr("#{SERIAL_KEYWORD}=", '')
16
+ else
17
+ puts 'ERROR: Invalid serial number response'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ class Zklib
2
+ module SSRManagement
3
+ SSR_KEYWORD = '~SSR'
4
+
5
+ # Get SSR
6
+ def get_ssr
7
+ execute_cmd(
8
+ command: CMD_DEVICE,
9
+ command_string: SSR_KEYWORD
10
+ ) do |opts|
11
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
12
+
13
+ data = opts[:data]
14
+ if data.length > 8
15
+ data.split("\u0000").pop.tr("#{SSR_KEYWORD}=", '')
16
+ else
17
+ puts 'ERROR: Invalid SSR response'
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,47 @@
1
+ class Zklib
2
+ module TimeManagement
3
+ # Get current time of attendance machine
4
+ def get_time
5
+ execute_cmd(
6
+ command: CMD_GET_TIME,
7
+ command_string: ''
8
+ ) do |opts|
9
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
10
+
11
+ data = opts[:data]
12
+ if data.length > 8
13
+ decode_time(seconds: BinData::Uint32le.read(data[8..-1]).snapshot)
14
+ else
15
+ puts 'ERROR: Invalid time response'
16
+ end
17
+ end
18
+ end
19
+
20
+ # Set current time for attendance machine
21
+ def set_time(time = Time.now)
22
+ seconds = encode_time(time: time)
23
+ command_buffer = StringIO.new
24
+ binary_writer = BinData::Uint32le.new
25
+
26
+ # Write command string
27
+ binary_writer.value = seconds
28
+ command_buffer.pos = 0
29
+ binary_writer.write(command_buffer)
30
+ command_string = command_buffer.string
31
+
32
+ execute_cmd(
33
+ command: CMD_SET_TIME,
34
+ command_string: command_string
35
+ ) do |opts|
36
+ return puts "ERROR: #{options[:error]}" unless opts[:valid]
37
+
38
+ data = opts[:data]
39
+ if data.length > 7
40
+ data.split("\u0000").pop
41
+ else
42
+ puts 'ERROR: Invalid time response'
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end