# -*- coding: utf-8 -*- import sys from datetime import datetime from socket import AF_INET, SOCK_DGRAM, socket from struct import pack, unpack from zk import const from zk.attendance import Attendance from zk.exception import ZKErrorResponse, ZKNetworkError from zk.user import User from zk.finger import Finger def make_commkey(key, session_id, ticks=50): """take a password and session_id and scramble them to send to the time clock. copied from commpro.c - MakeKey""" key = int(key) session_id = int(session_id) k = 0 for i in range(32): if (key & (1 << i)): k = (k << 1 | 1) else: k = k << 1 k += session_id k = pack(b'I', k) k = unpack(b'BBBB', k) k = pack( b'BBBB', k[0] ^ ord('Z'), k[1] ^ ord('K'), k[2] ^ ord('S'), k[3] ^ ord('O')) k = unpack(b'HH', k) k = pack(b'HH', k[1], k[0]) B = 0xff & ticks k = unpack(b'BBBB', k) k = pack( b'BBBB', k[0] ^ B, k[1] ^ B, B, k[3] ^ B) return k class ZK(object): """ Clase ZK """ def __init__(self, ip, port=4370, timeout=60, password=0, firmware=8): """ initialize instance """ self.is_connect = False self.__address = (ip, port) self.__sock = socket(AF_INET, SOCK_DGRAM) self.__sock.settimeout(timeout) self.__password = password # passint self.__firmware = int(firmware) #TODO check minor version? self.users = 0 self.fingers = 0 self.records = 0 self.dummy = 0 self.cards = 0 self.fingers_cap = 0 self.users_cap = 0 self.rec_cap = 0 self.fingers_av = 0 self.users_av = 0 self.rec_av = 0 self.__session_id = 0 self.__reply_id = const.USHRT_MAX-1 self.__data_recv = None def __create_header(self, command, command_string, session_id, reply_id): ''' Puts a the parts that make up a packet together and packs them into a byte string MODIFIED now, without initial checksum ''' #checksum = 0 always? for calculating buf = pack('HHHH', command, 0, session_id, reply_id) + command_string buf = unpack('8B' + '%sB' % len(command_string), buf) checksum = unpack('H', self.__create_checksum(buf))[0] reply_id += 1 if reply_id >= const.USHRT_MAX: reply_id -= const.USHRT_MAX buf = pack('HHHH', command, checksum, session_id, reply_id) return buf + command_string def __create_checksum(self, p): ''' Calculates the checksum of the packet to be sent to the time clock Copied from zkemsdk.c ''' l = len(p) checksum = 0 while l > 1: checksum += unpack('H', pack('BB', p[0], p[1]))[0] p = p[2:] if checksum > const.USHRT_MAX: checksum -= const.USHRT_MAX l -= 2 if l: checksum = checksum + p[-1] while checksum > const.USHRT_MAX: checksum -= const.USHRT_MAX checksum = ~checksum while checksum < 0: checksum += const.USHRT_MAX return pack('H', checksum) def __send_command(self, command, command_string='', response_size=8): ''' send command to the terminal ''' buf = self.__create_header(command, command_string, self.__session_id, self.__reply_id) try: self.__sock.sendto(buf, self.__address) 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.__reply_id = unpack('HHHH', self.__data_recv[:8])[3] if self.__response in [const.CMD_ACK_OK, const.CMD_PREPARE_DATA, const.CMD_DATA]: return { 'status': True, 'code': self.__response } return { 'status': False, 'code': self.__response } def __ack_ok(self): """ ack ok """ buf = self.__create_header(const.CMD_ACK_OK, "", self.__session_id, const.USHRT_MAX - 1) try: self.__sock.sendto(buf, self.__address) except Exception, e: raise ZKNetworkError(str(e)) def __get_data_size(self): """Checks a returned packet to see if it returned CMD_PREPARE_DATA, indicating that data packets are to be sent Returns the amount of bytes that are going to be sent""" response = self.__response if response == const.CMD_PREPARE_DATA: size = unpack('I', self.__data_recv[8:12])[0] return size else: 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) #print "decode from %s "% format(t, '04x') 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 __encode_time(self, t): """Encode a timestamp so that it can be read on the timeclock """ # formula taken from zkemsdk.c - EncodeTime # can also be found in the technical manual d = ( ((t.year % 100) * 12 * 31 + ((t.month - 1) * 31) + t.day - 1) * (24 * 60 * 60) + (t.hour * 60 + t.minute) * 60 + t.second ) return d def connect(self): ''' connect to the device ''' self.__session_id = 0 self.__reply_id = const.USHRT_MAX - 1 cmd_response = self.__send_command(const.CMD_CONNECT) self.__session_id = unpack('HHHH', self.__data_recv[:8])[2] if cmd_response.get('code')==const.CMD_ACK_UNAUTH: #print "try auth" command_string = make_commkey(self.__password, self.__session_id) cmd_response = self.__send_command(const.CMD_AUTH, command_string) if cmd_response.get('status'): self.is_connect = True # set the session iduid, privilege, password, name, card, group_id, timezone, user_id = unpack('HB5s8s5sBhI',userdata.ljust(28)[:28]) return self else: print "connect err {} ".format(cmd_response["code"]) raise ZKErrorResponse("Invalid response: Can't connect") def disconnect(self): ''' diconnect from the connected device ''' cmd_response = self.__send_command(const.CMD_EXIT) if cmd_response.get('status'): self.is_connect = False return True else: raise ZKErrorResponse("can't disconnect") def disable_device(self): ''' disable (lock) device, ensure no activity when process run ''' cmd_response = self.__send_command(const.CMD_DISABLEDEVICE) if cmd_response.get('status'): return True else: raise ZKErrorResponse("Can't Disable") def enable_device(self): ''' re-enable the connected device ''' cmd_response = self.__send_command(const.CMD_ENABLEDEVICE) if cmd_response.get('status'): return True else: raise ZKErrorResponse("Can't enable") def get_firmware_version(self): ''' return the firmware version ''' cmd_response = self.__send_command(const.CMD_GET_VERSION,'', 1024) if cmd_response.get('status'): firmware_version = self.__data_recv[8:].split('\x00')[0] return firmware_version else: raise ZKErrorResponse("Can't read frimware version") def get_serialnumber(self): ''' return the serial number ''' command = const.CMD_OPTIONS_RRQ command_string = '~SerialNumber' response_size = 1024 cmd_response = self.__send_command(command, command_string, response_size) if cmd_response.get('status'): serialnumber = self.__data_recv[8:].split('=')[-1].split('\x00')[0] return serialnumber else: raise ZKErrorResponse("can't read serial number") def get_platform(self): ''' return the serial number ''' command = const.CMD_OPTIONS_RRQ command_string = '~Platform' response_size = 1024 cmd_response = self.__send_command(command, command_string, response_size) if cmd_response.get('status'): platform = self.__data_recv[8:].split('=')[-1].split('\x00')[0] return platform else: raise ZKErrorResponse("can't get platform") def get_device_name(self): ''' return the serial number ''' command = const.CMD_OPTIONS_RRQ command_string = '~DeviceName' response_size = 1024 cmd_response = self.__send_command(command, command_string, response_size) if cmd_response.get('status'): device = self.__data_recv[8:].split('=')[-1].split('\x00')[0] return device else: raise ZKErrorResponse("can't read device name") def get_pin_width(self): ''' return the serial number ''' command = const.CMD_GET_PINWIDTH command_string = ' P' response_size = 9 cmd_response = self.__send_command(command, command_string, response_size) if cmd_response.get('status'): width = self.__data_recv[8:].split('\x00')[0] return bytearray(width)[0] else: raise ZKErrorResponse("can0t get pin width") def free_data(self): """ clear buffer""" command = const.CMD_FREE_DATA cmd_response = self.__send_command(command) if cmd_response.get('status'): return True else: raise ZKErrorResponse("can't free data") def read_sizes(self): """ read sizes """ command = const.CMD_GET_FREE_SIZES response_size = 1024 cmd_response = self.__send_command(command,'', response_size) if cmd_response.get('status'): fields = unpack('iiiiiiiiiiiiiiiiiiii', self.__data_recv[8:]) self.users = fields[4] self.fingers = fields[6] self.records = fields[8] self.dummy = fields[10] #??? self.cards = fields[12] self.fingers_cap = fields[14] self.users_cap = fields[15] self.rec_cap = fields[16] self.fingers_av = fields[17] self.users_av = fields[18] self.rec_av = fields[19] #TODO: get faces size... return True else: raise ZKErrorResponse("can't read sizes") def __str__(self): """ for debug""" return "ZK%i adr:%s:%s users:%i/%i fingers:%i/%i, records:%i/%i" % ( self.__firmware, self.__address[0], self.__address[1], self.users, self.users_cap, self.fingers, self.fingers_cap, self.records, self.rec_cap ) def restart(self): ''' restart the device ''' command = const.CMD_RESTART cmd_response = self.__send_command(command) if cmd_response.get('status'): return True else: raise ZKErrorResponse("can't restart device") def get_time(self): """obtener la hora del equipo""" command = const.CMD_GET_TIME response_size = 1032 cmd_response = self.__send_command(command, '', response_size) if cmd_response.get('status'): return self.__decode_time(self.__data_recv[8:12]) else: raise ZKErrorResponse("can't get time") def set_time(self, timestamp): """ colocar la hora del sistema al zk """ command = const.CMD_SET_TIME command_string = pack(b'I', self.__encode_time(timestamp)) cmd_response = self.__send_command(command, command_string) if cmd_response.get('status'): return True else: raise ZKErrorResponse("can't set time") def poweroff(self): ''' shutdown the device ''' command = const.CMD_POWEROFF command_string = '' response_size = 1032 cmd_response = self.__send_command(command, command_string, response_size) if cmd_response.get('status'): return True else: raise ZKErrorResponse("can't poweroff") def refresh_data(self): ''' shutdown the device ''' command = const.CMD_REFRESHDATA cmd_response = self.__send_command(command) if cmd_response.get('status'): return True else: raise ZKErrorResponse("can't refresh data") def test_voice(self, index=0): ''' play test voice 0 acceso correcto 1 password incorrecto 2 la memoria del terminal está llena 3 usuario invalido 4 intente de nuevo por favor * 5 reintroduszca codigo de usuario 6 memoria del terminal llena 7 memoria de alm fich llena 8 huella duplicada 9 acceso denegado 10 *beep* 11 el sistema vuelve al modo de verificacion 12 por favor coloque su dedo o acerque tarjeta 13 acerca su tarjeta de nuevo 14 excedido tiempo p esta operacion 15 coloque su dedo de nuevo 16 coloque su dedo por ultima vez 17 ATN numero de tarjeta está repetida 18 proceso de registro correcto * 19 borrado correcto 20 Numero de usuario 21 ATN se ha llegado al max num usuarios 22 verificacion de usuarios 23 usuario no registrado 24 ATN se ha llegado al num max de registros 25 ATN la puerta no esta cerrada 26 registro de usuarios 27 borrado de usuarios 28 coloque su dedo 29 registre la tarjeta de administrador 30 0 31 1 32 2 33 3 34 4 35 5 36 6 37 7 38 8 39 9 40 PFV seleccione numero de usuario 41 registrar 42 operacion correcta 43 PFV acerque su tarjeta 43 la tarjeta ha sido registrada 45 error en operacion 46 PFV acerque tarjeta de administracion, p confirmacion 47 descarga de fichajes 48 descarga de usuarios 49 carga de usuarios 50 actualizan de firmware 51 ejeuctar ficheros de configuracion 52 confirmación de clave de acceso correcta 53 error en operacion de tclado 54 borrar todos los usuarios 55 restaurar terminal con configuracion por defecto 56 introduzca numero de usuario 57 teclado bloqueado 58 error en la gestión de la tarjeta 59 establezca una clave de acceso 60 pulse el teclado 61 zona de accceso invalida 62 acceso combinado invĺlido 63 verificación multiusuario 64 modo de verificación inválido 65 - ''' command = const.CMD_TESTVOICE command_string = pack("I", index) cmd_response = self.__send_command(command, command_string) if cmd_response.get('status'): return True else: raise ZKErrorResponse("can't test voice") def set_user(self, uid, name, privilege=0, password='', group_id='', user_id='', card=0): ''' create or update user by uid ''' command = const.CMD_USER_WRQ if not user_id: user_id = str(uid) #ZK6 needs uid2 == uid #uid = chr(uid % 256) + chr(uid >> 8) if privilege not in [const.USER_DEFAULT, const.USER_ADMIN]: privilege = const.USER_DEFAULT privilege = chr(privilege) if self.__firmware == 6: print "uid : %i" % uid print "pri : %c" % privilege print "pass: %s" % str(password) print "name: %s" % str(name) print type(name) print "group %i" % int(group_id) print "uid2: %i" % int(user_id) try: command_string = pack('Hc5s8s5sBHI', uid, privilege, str(password), str(name), chr(0), int(group_id), 0, int(user_id)) print "cmd : %s" % command_string except Exception, e: print "s_h Error pack: %s" % e print "Error pack: %s" % sys.exc_info()[0] raise ZKErrorResponse("Cant pack user") else: command_string = pack('Hc8s28sc7sx24s', uid, privilege, password, name, chr(0), group_id, user_id) response_size = 1024 cmd_response = self.__send_command(command, command_string, response_size) if cmd_response.get('status'): return True else: raise ZKErrorResponse("Cant set user") def save_user_template(self, user, fingers=[]): """ save user and template """ # armar paquete de huellas if isinstance(fingers, Finger): fingers =[Finger] fpack = "" table = "" fnum = 0x10 # possibly flag tstart = 0 for finger in fingers: tfp = finger.repack_only() table += pack("> 8) #command_string = pack('2s', uid) command_string = pack('h', uid) cmd_response = self.__send_command(command, command_string) if cmd_response.get('status'): return True else: raise ZKErrorResponse("can't delete user") def get_user_template(self, uid, temp_id): command = 88 # comando secreto!!! command_string = pack('hb', uid, temp_id) response_size = 1024 cmd_response = self.__send_command(command, command_string, response_size) data = [] if not cmd_response.get('status'): return None #("can't get user template") #else if cmd_response.get('code') == const.CMD_PREPARE_DATA: bytes = self.__get_data_size() #TODO: check with size size = bytes while True: #limitado por respuesta no por tamaño data_recv = self.__sock.recv(1032) response = unpack('HHHH', data_recv[:8])[0] #print "# %s packet response is: %s" % (pac, response) if response == const.CMD_DATA: data.append(data_recv[8:]) #header turncated bytes -= 1024 elif response == const.CMD_ACK_OK: break #without problem. else: #truncado! continuar? #print "broken!" break #print "still needs %s" % bytes data = ''.join(data) #uid 32 fing 03, starts with 4d-9b-53-53-32-31 return Finger(size, uid, temp_id, 1, data) def get_templates(self): """ return array of all fingers """ templates = [] templatedata, size = self.read_with_buffer(const.CMD_DB_RRQ, const.FCT_FINGERTMP) if size < 4: print "WRN: no user data" # debug return [] total_size = unpack('i', templatedata[0:4])[0] templatedata = templatedata[4:] #total size not used if self.__firmware == 6: #tested! while total_size: size, uid, fid, valid = unpack('HHbb',templatedata[:6]) template = unpack("%is" % (size-6), templatedata[6:size])[0] finger = Finger(size, uid, fid, valid, template) print finger # test templates.append(finger) templatedata = templatedata[size:] total_size -= size else: # TODO: test!!! while total_size: size, uid, fid, valid = unpack('HHbb',templatedata[:6]) template = unpack("%is" % (size-6), templatedata[6:size])[0] finger = Finger(size - 6, uid, fid, valid, template) print finger # test templates.append(finger) templatedata = templatedata[(size):] total_size -= size return templates def get_users(self): """ return all user """ users = [] userdata, size = self.read_with_buffer(const.CMD_USERTEMP_RRQ, const.FCT_USER) print "user size %i" % size if size < 4: print "WRN: no user data" # debug return [] userdata = userdata[4:] #total size not used if self.__firmware == 6: while len(userdata) >= 28: uid, privilege, password, name, card, group_id, timezone, user_id = unpack('HB5s8s5sBhI',userdata.ljust(28)[:28]) password = unicode(password.split('\x00')[0], errors='ignore') name = unicode(name.split('\x00')[0], errors='ignore').strip() card = unpack('Q', card.ljust(8,'\x00'))[0] #or hex value? group_id = str(group_id) user_id = str(user_id) #TODO: check card value and find in ver8 if not name: name = "NN-%s" % user_id user = User(uid, name, privilege, password, group_id, user_id, card) users.append(user) print "[6]user:",uid, privilege, password, name, card, group_id, timezone, user_id userdata = userdata[28:] else: while len(userdata) >= 72: uid, privilege, password, name, sparator, group_id, user_id = unpack('Hc8s28sc7sx24s', userdata.ljust(72)[:72]) #u1 = int(uid[0].encode("hex"), 16) #u2 = int(uid[1].encode("hex"), 16) #uid = u1 + (u2 * 256) privilege = int(privilege.encode("hex"), 16) password = unicode(password.split('\x00')[0], errors='ignore') name = unicode(name.split('\x00')[0], errors='ignore').strip() group_id = unicode(group_id.split('\x00')[0], errors='ignore').strip() user_id = unicode(user_id.split('\x00')[0], errors='ignore') if not name: name = "NN-%s" % user_id user = User(uid, name, privilege, password, group_id, user_id) users.append(user) userdata = userdata[72:] return users def _get_users(self): ''' return all user ''' command = const.CMD_USERTEMP_RRQ command_string = chr(const.FCT_USER) response_size = 1024 cmd_response = self.__send_command(command, command_string, response_size) users = [] pac = 0 if cmd_response.get('status'): if cmd_response.get('code') == const.CMD_PREPARE_DATA: bytes = self.__get_data_size() userdata = [] while True: data_recv = self.__sock.recv(1032) response = unpack('HHHH', data_recv[:8])[0] if response == const.CMD_DATA: pac += 1 userdata.append(data_recv[8:]) #header turncated bytes -= 1024 elif response == const.CMD_ACK_OK: break #without problem. else: #truncado! continuar? #print "broken! with %s" % response #print "user still needs %s" % bytes break if response == const.CMD_ACK_OK: if userdata: # The first 4 bytes don't seem to be related to the user userdata = ''.join(userdata) userdata = userdata[4:] if self.__firmware == 6: while len(userdata) >= 28: uid, privilege, password, name, card, group_id, timezone, user_id = unpack('HB5s8s5sBhI',userdata.ljust(28)[:28]) password = unicode(password.split('\x00')[0], errors='ignore') name = unicode(name.split('\x00')[0], errors='ignore').strip() card = unpack('Q', card.ljust(8,'\x00'))[0] #or hex value? group_id = str(group_id) user_id = str(user_id) #TODO: check card value and find in ver8 if not name: name = "NN-%s" % user_id user = User(uid, name, privilege, password, group_id, user_id) users.append(user) print "[6]user:",uid, privilege, password, name, card, group_id, timezone, user_id userdata = userdata[28:] else: while len(userdata) >= 72: uid, privilege, password, name, sparator, group_id, user_id = unpack('Hc8s28sc7sx24s', userdata.ljust(72)[:72]) #u1 = int(uid[0].encode("hex"), 16) #u2 = int(uid[1].encode("hex"), 16) #uid = u1 + (u2 * 256) privilege = int(privilege.encode("hex"), 16) password = unicode(password.split('\x00')[0], errors='ignore') name = unicode(name.split('\x00')[0], errors='ignore').strip() group_id = unicode(group_id.split('\x00')[0], errors='ignore').strip() user_id = unicode(user_id.split('\x00')[0], errors='ignore') if not name: name = "NN-%s" % user_id user = User(uid, name, privilege, password, group_id, user_id) users.append(user) userdata = userdata[72:] self.free_data() else: raise ZKErrorResponse("can't _get user") return users def cancel_capture(self): ''' cancel capturing finger ''' command = const.CMD_CANCELCAPTURE cmd_response = self.__send_command(command) return bool(cmd_response.get('status')) def verify_user(self): ''' start verify finger mode (after capture) ''' command = const.CMD_STARTVERIFY # uid = chr(uid % 256) + chr(uid >> 8) cmd_response = self.__send_command(command) if cmd_response.get('status'): return True else: raise ZKErrorResponse("Cant Verify") def reg_event(self, flags): """ reg events, """ command = const.CMD_REG_EVENT command_string = pack ("I", flags) cmd_response = self.__send_command(command, command_string) if not cmd_response.get('status'): raise ZKErrorResponse("cant' reg events %i" % flags) def enroll_user(self, uid, temp_id=0): ''' start enroll user ''' command = const.CMD_STARTENROLL command_string = pack('hhb', uid, 0, temp_id) # el 0 es misterio cmd_response = self.__send_command(command, command_string) if not cmd_response.get('status'): raise ZKErrorResponse("Cant Enroll user #%i [%i]" %(uid, temp_id)) print "enroll", cmd_response #retorna rapido toca esperar un reg event attempts = 3 while attempts: print "A:%i esperando primer regevent" % attempts data_recv = self.__sock.recv(1032) # timeout? tarda bastante... self.__ack_ok() print (data_recv).encode('hex') if len(data_recv) > 8: #not empty res = unpack("H", data_recv.ljust(16,"\x00")[8:10])[0] print "res", res if res == 6: print ("posible timeout") return False print "A:%i esperando 2do regevent" % attempts data_recv = self.__sock.recv(1032) # timeout? tarda bastante... self.__ack_ok() print (data_recv).encode('hex') if len(data_recv) > 8: #not empty res = unpack("H", data_recv.ljust(16,"\x00")[8:10])[0] print "res", res if res == 6: print ("posible timeout") return False elif res == 0x64: print ("ok, continue?") attempts -= 1 print "esperando 3er regevent" data_recv = self.__sock.recv(1032) # timeout? tarda bastante... self.__ack_ok() print (data_recv).encode('hex') res = unpack("H", data_recv.ljust(16,"\x00")[8:10])[0] if res == 4: print "registro Fallido" self.cancel_capture() return False if res == 0: size = unpack("H", data_recv.ljust(16,"\x00")[10:12])[0] pos = unpack("H", data_recv.ljust(16,"\x00")[12:14])[0] print "enroll ok", size, pos return True def clear_data(self): ''' clear all data (include: user, attendance report, finger database ) ''' command = const.CMD_CLEAR_DATA cmd_response = self.__send_command(command) if cmd_response.get('status'): return True else: raise ZKErrorResponse("can't clear data") def __read_chunk(self, start, size): """ read a chunk from buffer """ command = 1504 #CMD_READ_BUFFER command_string = pack('= 8: uid, status, timestamp = unpack('HH4s', attendance_data.ljust(8)[:8]) attendance_data = attendance_data[8:] if uid == 0: #(on zk it's 16 bytes, extrauid 0, status 255, timestamp 0x0) continue # probably user_id = str(uid) #TODO revisar posibles valores cruzar con userdata timestamp = self.__decode_time(timestamp) attendance = Attendance(uid, user_id, timestamp, status) attendances.append(attendance) else: while len(attendance_data) >= 40: uid, user_id, sparator, timestamp, status, space = unpack('H24sc4sc8s', attendance_data.ljust(40)[:40]) user_id = user_id.split('\x00')[0] timestamp = self.__decode_time(timestamp) status = int(status.encode("hex"), 16) attendance = Attendance(uid, user_id, timestamp, status) attendances.append(attendance) attendance_data = attendance_data[40:] return attendances def _get_attendance(self): ''' return all attendance record ''' command = const.CMD_ATTLOG_RRQ command_string = '' response_size = 1024 cmd_response = self.__send_command(command, command_string, response_size) attendances = [] if cmd_response.get('status'): if cmd_response.get('code') == const.CMD_PREPARE_DATA: bytes = self.__get_data_size() attendance_data = [] pac = 1 while True: #limitado por respuesta no por tamaño data_recv = self.__sock.recv(1032) response = unpack('HHHH', data_recv[:8])[0] #print "# %s packet response is: %s" % (pac, response) if response == const.CMD_DATA: pac += 1 attendance_data.append(data_recv[8:]) #header turncated bytes -= 1024 elif response == const.CMD_ACK_OK: break #without problem. else: #truncado! continuar? #print "broken!" break #print "still needs %s" % bytes if response == const.CMD_ACK_OK: if attendance_data: attendance_data = ''.join(attendance_data) attendance_data = attendance_data[4:] if self.__firmware == 6: while len(attendance_data) >= 8: uid, status, timestamp = unpack('HH4s', attendance_data.ljust(8)[:8]) attendance_data = attendance_data[8:] if uid == 0: #(on zk it's 16 bytes, extrauid 0, status 255, timestamp 0x0) continue # probably user_id = str(uid) #TODO revisar posibles valores cruzar con userdata timestamp = self.__decode_time(timestamp) attendance = Attendance(uid, user_id, timestamp, status) attendances.append(attendance) else: while len(attendance_data) >= 40: uid, user_id, sparator, timestamp, status, space = unpack('H24sc4sc8s', attendance_data.ljust(40)[:40]) user_id = user_id.split('\x00')[0] timestamp = self.__decode_time(timestamp) status = int(status.encode("hex"), 16) attendance = Attendance(uid, user_id, timestamp, status) attendances.append(attendance) attendance_data = attendance_data[40:] self.free_data() else: raise ZKErrorResponse("can't _get attendance") return attendances def clear_attendance(self): ''' clear all attendance record ''' command = const.CMD_CLEAR_ATTLOG cmd_response = self.__send_command(command, command_string) if cmd_response.get('status'): return True else: raise ZKErrorResponse("can't clear response")