Merge branch 'dev'
This commit is contained in:
commit
a92f712851
12
zk/attendance.py
Normal file
12
zk/attendance.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
class Attendance(object):
|
||||||
|
def __init__(self, user_id, timestamp, status):
|
||||||
|
self.user_id = user_id
|
||||||
|
self.timestamp = timestamp
|
||||||
|
self.status = status
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.user_id
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<Attendance>: {}'.format(self.user_id)
|
197
zk/base.py
197
zk/base.py
@ -1,8 +1,11 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
from datetime import datetime
|
||||||
from struct import pack, unpack
|
from struct import pack, unpack
|
||||||
from socket import socket, AF_INET, SOCK_DGRAM
|
from socket import socket, AF_INET, SOCK_DGRAM
|
||||||
|
|
||||||
from zk import const
|
from zk import const
|
||||||
|
from zk.exception import ZKErrorResponse, ZKNetworkError
|
||||||
|
from zk.attendance import Attendance
|
||||||
from zk.user import User
|
from zk.user import User
|
||||||
|
|
||||||
class ZK(object):
|
class ZK(object):
|
||||||
@ -59,9 +62,16 @@ class ZK(object):
|
|||||||
return pack('H', checksum)
|
return pack('H', checksum)
|
||||||
|
|
||||||
def __send_command(self, command, command_string, checksum, session_id, reply_id, response_size):
|
def __send_command(self, command, command_string, checksum, session_id, reply_id, response_size):
|
||||||
|
'''
|
||||||
|
send command to the terminal
|
||||||
|
'''
|
||||||
buf = self.__create_header(command, command_string, checksum, session_id, reply_id)
|
buf = self.__create_header(command, command_string, checksum, session_id, reply_id)
|
||||||
|
try:
|
||||||
self.__sock.sendto(buf, self.__address)
|
self.__sock.sendto(buf, self.__address)
|
||||||
self.__data_recv = self.__sock.recv(response_size)
|
self.__data_recv = self.__sock.recv(response_size)
|
||||||
|
except Exception, e:
|
||||||
|
raise ZKNetworkError(str(e))
|
||||||
|
|
||||||
self.__response = unpack('HHHH', self.__data_recv[:8])[0]
|
self.__response = unpack('HHHH', self.__data_recv[:8])[0]
|
||||||
self.__reply_id = unpack('HHHH', self.__data_recv[:8])[3]
|
self.__reply_id = unpack('HHHH', self.__data_recv[:8])[3]
|
||||||
|
|
||||||
@ -88,9 +98,43 @@ class ZK(object):
|
|||||||
else:
|
else:
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def __reverse_hex(self, hex):
|
||||||
|
data = ''
|
||||||
|
for i in reversed( xrange( len(hex)/2 ) ):
|
||||||
|
data += hex[i*2:(i*2)+2]
|
||||||
|
return data
|
||||||
|
|
||||||
|
def __decode_time(self, t):
|
||||||
|
"""Decode a timestamp retrieved from the timeclock
|
||||||
|
|
||||||
|
copied from zkemsdk.c - DecodeTime"""
|
||||||
|
t = t.encode('hex')
|
||||||
|
t = int(self.__reverse_hex(t), 16)
|
||||||
|
|
||||||
|
second = t % 60
|
||||||
|
t = t / 60
|
||||||
|
|
||||||
|
minute = t % 60
|
||||||
|
t = t / 60
|
||||||
|
|
||||||
|
hour = t % 24
|
||||||
|
t = t / 24
|
||||||
|
|
||||||
|
day = t % 31+1
|
||||||
|
t = t / 31
|
||||||
|
|
||||||
|
month = t % 12+1
|
||||||
|
t = t / 12
|
||||||
|
|
||||||
|
year = t + 2000
|
||||||
|
|
||||||
|
d = datetime(year, month, day, hour, minute, second)
|
||||||
|
|
||||||
|
return d
|
||||||
|
|
||||||
def connect(self):
|
def connect(self):
|
||||||
'''
|
'''
|
||||||
connect to device
|
connect to the device
|
||||||
'''
|
'''
|
||||||
|
|
||||||
command = const.CMD_CONNECT
|
command = const.CMD_CONNECT
|
||||||
@ -107,11 +151,11 @@ class ZK(object):
|
|||||||
self.__sesion_id = unpack('HHHH', self.__data_recv[:8])[2]
|
self.__sesion_id = unpack('HHHH', self.__data_recv[:8])[2]
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid response")
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
def disconnect(self):
|
def disconnect(self):
|
||||||
'''
|
'''
|
||||||
diconnect from connected device
|
diconnect from the connected device
|
||||||
'''
|
'''
|
||||||
|
|
||||||
command = const.CMD_EXIT
|
command = const.CMD_EXIT
|
||||||
@ -125,11 +169,11 @@ class ZK(object):
|
|||||||
if cmd_response.get('status'):
|
if cmd_response.get('status'):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid response")
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
def disable_device(self):
|
def disable_device(self):
|
||||||
'''
|
'''
|
||||||
disable (lock) connected device, make sure no activity when process run
|
disable (lock) device, ensure no activity when process run
|
||||||
'''
|
'''
|
||||||
|
|
||||||
command = const.CMD_DISABLEDEVICE
|
command = const.CMD_DISABLEDEVICE
|
||||||
@ -143,11 +187,11 @@ class ZK(object):
|
|||||||
if cmd_response.get('status'):
|
if cmd_response.get('status'):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid response")
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
def enable_device(self):
|
def enable_device(self):
|
||||||
'''
|
'''
|
||||||
re-enable connected device
|
re-enable the connected device
|
||||||
'''
|
'''
|
||||||
|
|
||||||
command = const.CMD_ENABLEDEVICE
|
command = const.CMD_ENABLEDEVICE
|
||||||
@ -161,11 +205,11 @@ class ZK(object):
|
|||||||
if cmd_response.get('status'):
|
if cmd_response.get('status'):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid response")
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
def get_firmware_version(self):
|
def get_firmware_version(self):
|
||||||
'''
|
'''
|
||||||
get firmware version name
|
return the firmware version
|
||||||
'''
|
'''
|
||||||
|
|
||||||
command = const.CMD_GET_VERSION
|
command = const.CMD_GET_VERSION
|
||||||
@ -180,11 +224,29 @@ class ZK(object):
|
|||||||
firmware_version = self.__data_recv[8:].strip('\x00|\x01\x10x')
|
firmware_version = self.__data_recv[8:].strip('\x00|\x01\x10x')
|
||||||
return firmware_version
|
return firmware_version
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid response")
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
|
def get_serialnumber(self):
|
||||||
|
'''
|
||||||
|
return the serial number
|
||||||
|
'''
|
||||||
|
command = const.CMD_OPTIONS_RRQ
|
||||||
|
command_string = '~SerialNumber'
|
||||||
|
checksum = 0
|
||||||
|
session_id = self.__sesion_id
|
||||||
|
reply_id = self.__reply_id
|
||||||
|
response_size = 1024
|
||||||
|
|
||||||
|
cmd_response = self.__send_command(command, command_string, checksum, session_id, reply_id, response_size)
|
||||||
|
if cmd_response.get('status'):
|
||||||
|
serialnumber = self.__data_recv[8:].split('=')[-1].strip('\x00|\x01\x10x')
|
||||||
|
return serialnumber
|
||||||
|
else:
|
||||||
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
def restart(self):
|
def restart(self):
|
||||||
'''
|
'''
|
||||||
restart connected device
|
restart the device
|
||||||
'''
|
'''
|
||||||
|
|
||||||
command = const.CMD_RESTART
|
command = const.CMD_RESTART
|
||||||
@ -198,11 +260,11 @@ class ZK(object):
|
|||||||
if cmd_response.get('status'):
|
if cmd_response.get('status'):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid response")
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
def power_off(self):
|
def poweroff(self):
|
||||||
'''
|
'''
|
||||||
shutdown connected device
|
shutdown the device
|
||||||
'''
|
'''
|
||||||
|
|
||||||
command = const.CMD_POWEROFF
|
command = const.CMD_POWEROFF
|
||||||
@ -216,7 +278,7 @@ class ZK(object):
|
|||||||
if cmd_response.get('status'):
|
if cmd_response.get('status'):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid response")
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
def test_voice(self):
|
def test_voice(self):
|
||||||
'''
|
'''
|
||||||
@ -234,7 +296,7 @@ class ZK(object):
|
|||||||
if cmd_response.get('status'):
|
if cmd_response.get('status'):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid response")
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
def set_user(self, uid, name, privilege, password='', group_id='', user_id=''):
|
def set_user(self, uid, name, privilege, password='', group_id='', user_id=''):
|
||||||
'''
|
'''
|
||||||
@ -258,11 +320,31 @@ class ZK(object):
|
|||||||
if cmd_response.get('status'):
|
if cmd_response.get('status'):
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid response")
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
|
def delete_user(self, uid):
|
||||||
|
'''
|
||||||
|
delete specific user by uid
|
||||||
|
'''
|
||||||
|
command = const.CMD_DELETE_USER
|
||||||
|
|
||||||
|
uid = chr(uid % 256) + chr(uid >> 8)
|
||||||
|
|
||||||
|
command_string = pack('2s', uid)
|
||||||
|
checksum = 0
|
||||||
|
session_id = self.__sesion_id
|
||||||
|
reply_id = self.__reply_id
|
||||||
|
response_size = 1024
|
||||||
|
|
||||||
|
cmd_response = self.__send_command(command, command_string, checksum, session_id, reply_id, response_size)
|
||||||
|
if cmd_response.get('status'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
def get_users(self):
|
def get_users(self):
|
||||||
'''
|
'''
|
||||||
get all users
|
return all user
|
||||||
'''
|
'''
|
||||||
|
|
||||||
command = const.CMD_USERTEMP_RRQ
|
command = const.CMD_USERTEMP_RRQ
|
||||||
@ -311,7 +393,7 @@ class ZK(object):
|
|||||||
|
|
||||||
userdata = userdata[72:]
|
userdata = userdata[72:]
|
||||||
else:
|
else:
|
||||||
raise Exception("Invalid response")
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
return users
|
return users
|
||||||
|
|
||||||
@ -345,23 +427,86 @@ class ZK(object):
|
|||||||
cmd_response = self.__send_command(command=command, command_string=command_string)
|
cmd_response = self.__send_command(command=command, command_string=command_string)
|
||||||
print cmd_response
|
print cmd_response
|
||||||
|
|
||||||
def clear_user(self):
|
def clear_data(self):
|
||||||
'''
|
'''
|
||||||
Not implemented yet
|
clear all data (include: user, attendance report, finger database )
|
||||||
'''
|
'''
|
||||||
|
command = const.CMD_CLEAR_DATA
|
||||||
|
command_string = ''
|
||||||
|
checksum = 0
|
||||||
|
session_id = self.__sesion_id
|
||||||
|
reply_id = self.__reply_id
|
||||||
|
response_size = 1024
|
||||||
|
|
||||||
pass
|
cmd_response = self.__send_command(command, command_string, checksum, session_id, reply_id, response_size)
|
||||||
|
if cmd_response.get('status'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
def get_attendance(self):
|
def get_attendance(self):
|
||||||
'''
|
'''
|
||||||
Not implemented yet
|
return all attendance record
|
||||||
'''
|
'''
|
||||||
|
command = const.CMD_ATTLOG_RRQ
|
||||||
|
command_string = ''
|
||||||
|
checksum = 0
|
||||||
|
session_id = self.__sesion_id
|
||||||
|
reply_id = self.__reply_id
|
||||||
|
response_size = 1024
|
||||||
|
|
||||||
|
cmd_response = self.__send_command(command, command_string, checksum, session_id, reply_id, response_size)
|
||||||
|
attendances = []
|
||||||
|
if cmd_response.get('status'):
|
||||||
|
if cmd_response.get('code') == const.CMD_PREPARE_DATA:
|
||||||
|
bytes = self.__get_data_size()
|
||||||
|
attendance_data = []
|
||||||
|
while bytes > 0:
|
||||||
|
data_recv = self.__sock.recv(1032)
|
||||||
|
attendance_data.append(data_recv)
|
||||||
|
bytes -= 1024
|
||||||
|
|
||||||
|
data_recv = self.__sock.recv(8)
|
||||||
|
response = unpack('HHHH', data_recv[:8])[0]
|
||||||
|
if response == const.CMD_ACK_OK:
|
||||||
|
if attendance_data:
|
||||||
|
# The first 4 bytes don't seem to be related to the user
|
||||||
|
for x in xrange(len(attendance_data)):
|
||||||
|
if x > 0:
|
||||||
|
attendance_data[x] = attendance_data[x][8:]
|
||||||
|
|
||||||
|
attendance_data = ''.join(attendance_data)
|
||||||
|
attendance_data = attendance_data[14:]
|
||||||
|
while len(attendance_data) >= 38:
|
||||||
|
user_id, sparator, timestamp, status, space = unpack( '24sc4sc10s', attendance_data.ljust(40)[:40])
|
||||||
|
|
||||||
|
user_id = user_id.strip('\x00|\x01\x10x')
|
||||||
|
timestamp = self.__decode_time(timestamp)
|
||||||
|
status = int(status.encode("hex"), 16)
|
||||||
|
|
||||||
|
attendance = Attendance(user_id, timestamp, status)
|
||||||
|
attendances.append(attendance)
|
||||||
|
|
||||||
|
attendance_data = attendance_data[40:]
|
||||||
|
else:
|
||||||
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
|
||||||
|
return attendances
|
||||||
|
|
||||||
pass
|
|
||||||
|
|
||||||
def clear_attendance(self):
|
def clear_attendance(self):
|
||||||
'''
|
'''
|
||||||
Not implemented yet
|
clear all attendance record
|
||||||
'''
|
'''
|
||||||
|
command = const.CMD_CLEAR_ATTLOG
|
||||||
|
command_string = ''
|
||||||
|
checksum = 0
|
||||||
|
session_id = self.__sesion_id
|
||||||
|
reply_id = self.__reply_id
|
||||||
|
response_size = 1024
|
||||||
|
|
||||||
pass
|
cmd_response = self.__send_command(command, command_string, checksum, session_id, reply_id, response_size)
|
||||||
|
if cmd_response.get('status'):
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
raise ZKErrorResponse("Invalid response")
|
||||||
|
8
zk/exception.py
Normal file
8
zk/exception.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
class ZKError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ZKErrorResponse(ZKError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
class ZKNetworkError(ZKError):
|
||||||
|
pass
|
@ -9,5 +9,8 @@ class User(object):
|
|||||||
self.group_id = group_id
|
self.group_id = group_id
|
||||||
self.user_id = user_id
|
self.user_id = user_id
|
||||||
|
|
||||||
def __str__(self):
|
def __repr__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return '<User>: {}'.format(self.name)
|
Loading…
Reference in New Issue
Block a user