2

嗨,我需要从 c3-400 设备获取实时事件,我使用了 zkpull sdk 文档中描述的 GetRTlog 方法,但它总是返回门/警报状态并且从不返回实时事件。我使用此代码与使用 tcp/ip 配置了 192.168.52.249 ip 地址的 c3-400 访问设备进行通信,只有当设备中没有实时事件时它才应该返回门/警报状态,但它虽然有是设备上的事件我在这里做错了什么,任何人都可以帮忙

要重现这个,你需要一个 c3-400 设备,带有 zkpull sdk dll 文件的 windows 机器

          zk = ZK('192.168.52.249')
          zk.connect() 
          n=5
         while n > 0:
             events = zk.read_events()
             for e in events:
                 res='{}"code":[{}"event_type":"{}","door":"{}","card":"{}","pin":"{}","time":"{}","entry_exit":"{}","verify_mode":"{}"{}]{}'.format("{","{",e.event_type,e.door,e.card,e.pin,"",e.entry_exit,e.verify_mode,"}","}")


                print('res',res)

             n -= 1
             time.sleep(1)
      zk.disconnect()

ZK 码是

import ctypes
from .ZKEnum import *


class ZKRealtimeEvent:
    """
    Represents one realtime event occured on the device
    Since the device returns event as string we need to parse it to the structured view. This class does this.
    """
    __slots__ = (
        'time',
        'pin',
        'card',
        'door',
        'event_type',
        'entry_exit',
        'verify_mode'
    )

    def __init__(self, s=None):
        """
        :param s: Optional. Event string to be parsed.
        """
        if s:
            self.parse(s)

    def parse(self, s):
        """
        Parse one event string and fills out slots
        :param s: event string
        :raises ValueError: event string is invalid
        :return:
        """
        if s == '' or s == '\r\n':
            raise ValueError("Empty event string")

        items = s.split(',')
        if len(items) != 7:
            raise ValueError("Event string has not 7 comma-separated parts")

        items[0] = datetime.strptime(items[0], '%Y-%m-%d %H:%M:%S')
        #items[0] = items[0]
        for i in range(len(self.__slots__)):
            setattr(self, self.__slots__[i], items[i])

class ZK():



    @property
    def device_model(self):
        """Device model class. Read only"""
        return self._device_model

    def __init__(self,ip='192.168.52.249',device_model=ZK400):
        self.ip=ip
        self.connect_params='protocol=TCP,ipaddress={},port=4370,timeout=4000,passwd='.format(ip)
        self.handle=False
        self._device_model=device_model
        # self.session_id = 0
        # self.reply_number = 0
        # self.connected_flg = False 

    def __str__(self):
        return 'ZK access class'

    def connect(self):
        if(self.handle):
            raise RuntimeError('Already connected')
        self.connect_buffer=ctypes.create_string_buffer(self.connect_params.encode('utf-8'))
        self.commpro=ctypes.windll.LoadLibrary("plcommpro.dll")
        self.handle=self.commpro.Connect(self.connect_buffer)

        if self.handle ==0:
            raise RuntimeError('Coud not connect to '+self.ip)

    def disconnect(self):
        """
        Disconnect from device
        :return:
        """
        if not self.handle:
            return

        ret=self.commpro.Disconnect(self.handle)
        if ret ==0:
            raise RuntimeError('Coud not disconnect from '+self.ip)
        self.handle = False


    def getDeviceParam(self ,params=False):
        if not params:
            params="DeviceID,LockCount,GATEIPAddress,NetMask"
        my_buffer=ctypes.create_string_buffer(10*1024*1024)
        items = bytes(params,'utf-8')
        p_items = ctypes.create_string_buffer(items)
        ret = self.commpro.GetDeviceParam(self.handle,my_buffer,256,p_items)
        if ERRORS.get(ret):
            raise RuntimeError(ERRORS.get(ret)+' '+self.ip)
        rett=my_buffer.value.decode('utf-8')
        result=rett.split('\r\n')
        result=result[0]
        result_arr=result.split(',')
        result_dic={}
        for r in result_arr:
            x=r.split('=')
            result_dic[x[0]]=x[1]
        return result_dic

    def setDeviceParam(self ,params=False):
        if not params:
            raise RuntimeError('setDeviceParam params is missing')
        items = bytes(params,'utf-8')
        p_items = ctypes.create_string_buffer(items)
        ret = self.commpro.SetDeviceParam(self.handle,p_items)
        if ERRORS.get(ret):
            raise RuntimeError(ERRORS.get(ret)+' '+self.ip)
        return ret

    def editCardZone(self, zone_id,card):
        tablev=b"userauthorize"
        datdav="Pin="+str(card.pk)+"\tAuthorizeTimezoneId="+str(zone_id)
        datav=bytes(datdav,'utf-8')
        p_tablev=ctypes.create_string_buffer(tablev)
        str_bufv=ctypes.create_string_buffer(datav)
        res=self.commpro.SetDeviceData(self.handle, p_tablev, str_bufv, '')
        if ERRORS.get(res):
            raise RuntimeError(ERRORS.get(res)+' '+self.ip)
        return res

    def addCard(self, pin,cardno,password,zone=1,doors=15):
        pin=str(pin)
        cardno=str(cardno)
        password=str(password)
        table=b"user"
        datda="Pin="+pin+"\tCardNo="+cardno+"\tPassword="+password
        data=bytes(datda,'utf-8') 
        tablev=b"userauthorize"
        datdav="Pin="+pin+"\tAuthorizeTimezoneId="+str(zone)+"\tAuthorizeDoorId="+str(doors)
        datav=bytes(datdav,'utf-8')
        p_tablev=ctypes.create_string_buffer(tablev)
        str_bufv=ctypes.create_string_buffer(datav)
        self.commpro.SetDeviceData(self.handle, p_tablev, str_bufv, '')
        p_table=ctypes.create_string_buffer(table)
        str_buf=ctypes.create_string_buffer(data)
        res=self.commpro.SetDeviceData(self.handle,p_table,str_buf,'')

        if ERRORS.get(res):
            raise RuntimeError(ERRORS.get(res)+' '+self.ip) 
        return res

    def getCard(self):
        table = b"USER" # Download the user data from the user table
        fieldname = b"*" # Download all field information in the table
        pfilter = b"" # Have no filtering conditions and thus download all information
        options = b""
        query_buf = ctypes.create_string_buffer(4*1024*1024)
        query_table = ctypes.create_string_buffer(table)
        query_fieldname = ctypes.create_string_buffer(fieldname)
        query_filter = ctypes.create_string_buffer(pfilter)
        query_options = ctypes.create_string_buffer(options)
        ret = self.commpro.GetDeviceData(self.handle, query_buf, 4*1024*1024, query_table, query_fieldname, query_filter, query_options)
        if ERRORS.get(ret):
            raise RuntimeError(ERRORS.get(ret)+' '+self.ip)
        rett=query_buf.value.decode('utf-8')
        return rett.split('\r\n')

    def removeCard(self,pin):
        table=b"user"
        pin=str(pin)
        data=bytes("Pin="+pin, 'utf-8')
        p_table=ctypes.create_string_buffer(table)
        p_data=ctypes.create_string_buffer(data)
        res=self.commpro.DeleteDeviceData(self.handle,p_table,p_data,'')
        if ERRORS.get(res):
            raise RuntimeError(ERRORS.get(res)+' '+self.ip)
        return res 

    def addTimeZone(self,datda):
        table=b"timezone"
        data=bytes(datda,'utf-8') 
        p_table=ctypes.create_string_buffer(table)
        str_buf=ctypes.create_string_buffer(data)
        res=self.commpro.SetDeviceData(self.handle,p_table,str_buf,'')
        if ERRORS.get(res):
            raise RuntimeError(ERRORS.get(res)+' '+self.ip)
        return res


    def getTimeZones(self):
        table = b"timezone" # Download the user data from the user table
        fieldname = b"*" # Download all field information in the table
        pfilter = b"" # Have no filtering conditions and thus download all information
        options = b""
        query_buf = ctypes.create_string_buffer(4*1024*1024)
        query_table = ctypes.create_string_buffer(table)
        query_fieldname = ctypes.create_string_buffer(fieldname)
        query_filter = ctypes.create_string_buffer(pfilter)
        query_options = ctypes.create_string_buffer(options)
        ret = self.commpro.GetDeviceData(self.handle, query_buf, 4*1024*1024, query_table, query_fieldname, query_filter, query_options)
        if ERRORS.get(res):
            raise RuntimeError(ERRORS.get(res)+' '+self.ip)        
        rett=query_buf.value.decode('utf-8')
        result=rett.split('\r\n')
        result1=result[0]
        result2=result[1]
        result_arr1=result1.split(',')
        result_arr2=result2.split(',')
        result_dic={}
        zones_ids=[]
        for x in range(len(result)-2):
            result_dic={}
            arr=(result[x+1]).split(',')
            zones_ids.append(arr[0])
            # for num , param in enumerate(result_arr1):
            #     result_dic[param]=result_arr2[num]
        # for num , param in enumerate(result_arr1):
        #     result_dic[param]=result_arr2[num]
        return zones_ids
    def editTimeZone(self, edit_str):
        tablev=b"timezone"
        datav=bytes(edit_str,'utf-8')
        p_tablev=ctypes.create_string_buffer(tablev)
        str_bufv=ctypes.create_string_buffer(datav)
        res=self.commpro.SetDeviceData(self.handle, p_tablev, str_bufv, '')
        if ERRORS.get(res):
            raise RuntimeError(ERRORS.get(res)+' '+self.ip)
        return res

    def removeTimeZone(self,zone_id):
        table=b"timezone"
        timeId=str(zone_id)
        data=bytes("TimezoneId="+timeId, 'utf-8')
        p_table=ctypes.create_string_buffer(table)
        p_data=ctypes.create_string_buffer(data)
        res=self.commpro.DeleteDeviceData(self.handle,p_table,p_data,'')
        if ERRORS.get(res):
            raise RuntimeError(ERRORS.get(res)+' '+self.ip)
        return data

    def getAccessLogs(self):
        formmated_events=[]
        events=self.transaction()
        events.pop(0)
        events = events[:-1]
        elem=None
        for event in events:
            elem=event.split(',')
            if elem[0]!='0':
                date=formatTime(elem[6])
                obj={
                'card_no':elem[0],
                'pin':elem[1],
                'verified':VERIFY_MODES.get(elem[2]),
                'door_id':elem[3],
                'event_type':EVENT_TYPES.get(elem[4]),
                'in_out_state':elem[5],
                'time_stamp':date
                }
                formmated_events.append(obj)



        return formmated_events
    def transaction(self):
        table = b"transaction" # Download the user data from the user table
        fieldname = b"*" # Download all field information in the table
        pfilter = b"" # Have no filtering conditions and thus download all information
        options = b""
        query_buf = ctypes.create_string_buffer(4*1024*1024)
        query_table = ctypes.create_string_buffer(table)
        query_fieldname = ctypes.create_string_buffer(fieldname)
        query_filter = ctypes.create_string_buffer(pfilter)
        query_options = ctypes.create_string_buffer(options)
        ret = self.commpro.GetDeviceData(self.handle, query_buf, 4*1024*1024, query_table, query_fieldname, query_filter, query_options)

        if ERRORS.get(ret):
            raise RuntimeError(ERRORS.get(ret)+' '+self.ip)

        rett=query_buf.value.decode('utf-8')
        rett=rett.split('\r\n')
        return rett

    def getDeviceDataCount(self):
        table=ctypes.create_string_buffer(b"user")         
        table_filter=ctypes.create_string_buffer(b"") 
        options=ctypes.create_string_buffer(b"")
        ret = self.commpro.GetDeviceData(self.handle,table,table_filter,options)
        print(ret)
    def deleteDeviceData(self):
        pass  
    def searchDevice(self):
        pass
    def modifyIPAddress(self):
        pass
    def openDoor(self,num,group=1):
        self.enable_relay(group,num)


    def getRTLog(self, buffer_size=4096):
        """
        Machinery method for retrieving events from device.
        :param buffer_size: Required. Buffer size in bytes that filled with contents
        :raises RuntimeError: if operation was failed
        :return: raw string with events
        """
        buf = ctypes.create_string_buffer(buffer_size)

        res = self.commpro.GetRTLog(self.handle, buf, buffer_size)
        if ERRORS.get(res):
            raise RuntimeError(ERRORS.get(ret)+' '+self.ip)
        ret=buf.value.decode('utf-8')
        print('rrrrrrrrrrrrr',ret)
        return ret

    def read_events(self, buffer_size=4096):
        """
        Read events from the device
        :param buffer_size:
        :return:
        """
        raw = self.getRTLog(buffer_size)
        *events_s, empty = raw.split('\r\n')

        return (ZKRealtimeEvent(s) for s in events_s)

    def enable_relay(self, group=1, number=2, timeout=10):
        """
        Enable specified relay for the given time. Already enabled relay keep its state, but timeout overwrites with new
        value.
        :param group: Relay group, see RelayGroup enum. Number between 1 and 4
        :param number: Relay number in specified group
        :param timeout: Seconds the relay will be enabled. Number between 0 and 255
        :raises ValueError: invalid parameter
        :raises RuntimeError: operation failed
        :return:
        """
        if number < 1 or number > self.device_model.relays:
            raise ValueError("Incorrect relay number: {}".format(number))
        if timeout < 0 or timeout > 255:
            raise ValueError("Incorrect timeout: {}".format(timeout))

        self.controlDevice(
            ControlOperation.output,
            number,
            group,
            timeout,
            0
        )

    def controlDevice(self, operation, p1, p2, p3, p4, options_str=''):
        """
        Device control machinery method. Read PULL SDK docs for parameters meaning
        :param operation: Number, operation id
        :param p1: Number, depends on operation id
        :param p2: Number, depends on operation id
        :param p3: Number, depends on operation id
        :param p4: Number, depends on operation id
        :param options_str: String, depends on operation id
        :raises RuntimeError: if operation was failed
        :return: dll function result code, 0 or positive number
        """
        res = self.commpro.ControlDevice(
            self.handle,
            operation,
            p1,
            p2,
            p3,
            p4,
            options_str
        )
        if res < 0:
            raise RuntimeError('ControlDevice failed, params: ({}), returned: {}'.format(
                ','.join((str(self.handle), str(operation), str(p1), str(p2), str(p3), str(p4), str(options_str))),
                str(res)
            ))

        return res

和枚举代码是



class ControlOperation:
    """
    Type of device control operation. See PULL SDK docs
    """
    output = 1
    cancel_alarm = 2
    restart = 3


class RelayGroup:
    """
    Device relay group. See PULL SDK docs
    """
    lock = 1
    aux = 2



VERIFY_MODES = {
    '1':   'Only finger',
    '3':   'Only password',
    '4':   'Only card',
    '11':  'Card and password',
    '200': 'Others'
}
ERRORS = {
    '-1':   'The command is not sent successfully',
    '-2':   'The command has no response',
    '-3':   'The buffer is not enough',
    '-4':   'The decompression fails',
    '-5':   'The length of the read data is not correct ',
    '-6':   'The length of the decompressed data is not consistent with expected',
    '-7':   'The command is repeated ',
    '-8':   'The connection is not authorized ',
    '-9':   'Data error: The CRC result is failure',
    '-10':   'Data error: PullSDK cannot resolve the data ',
    '-11':   'Data parameter error',
    '-12':   'The command is not executed correctly',
    '-13':   'Command error: This command is not available ',
    '-14':   'The communication password is not correct',
    '-15':   'Fail to write the file',
    '-16':   'Fail to read the file',
    '-17':   'The file does not exist',
    '-99':   'Uknown error',
    '-100':   'The table structure does not exist ',
    '-101':   'In the table structure, In the table structure, In the table structure',
    '-102':   'The total number of fields is not consistent  ',
    '-103':   'The sequence of fields is not consistent  ',
    '-104':   'Real-time event data error ',
    '-105':   'Data errors occur during data resolution. ',
    '-106':   'Data overflow: The delivered data is more than 4 MB in length ',
    '-107':   'Fail to get the table structure  ',
    '-108':   'Invalid options',
    '-201':   'LoadLibrary failure  ',
    '-202':   'Fail to invoke the interface  ',
    '-203':   'Communication initialization fails ',
    '-206':   'Start of a serial interface agent program fails and the cause generally relies in  inexistence or occupation of the serial interface.',
    '-301':   'Requested TCP/IP version errorRequested TCP/IP version error ',
    '-302':   'Incorrect version number  ',
    '-303':   'Fail to get the protocol type',
    '-304':   'Invalid SOCKET',
    '-305':   'SOCKET error',
    '-306':   'HOST error',
    '-307':   'Connection attempt failed',
    '10035':   'Resources temporarily unavailable.',
    '10038':   'An operation was attempted on something that is not a socket.',
    '10054':   'Connection reset by peer.',
    '10060':   'Connection timed out.',
    '10061':   'Connection refused.',
    '10065':   'No route to host.',
}
EVENT_TYPES = {
    '0':   'Normal Punch Open',
    '1':   'Punch during Normal Open Time Zone',
    '2':   'First Card Normal Open (Punch Card)',
    '3':   'Multi-Card Open (Punching Card)',
    '4':   'Emergency Password Open',
    '5':   'Open during Normal Open Time Zone',
    '6':   'Linkage Event Triggered',
    '7':   'Cancel Alarm',
    '8':   'Remote Opening',
    '9':   'Remote Closing',
    '10':  'Disable Intraday Normal Open Time Zone',
    '11':  'Enable Intraday Normal Open Time Zone',
    '12':  'Open Auxiliary Output',
    '13':  'Close Auxiliary Output',
    '14':  'Press Fingerprint Open',
    '15':  'Multi-Card Open (Press Fingerprint)',
    '16':  'Press Fingerprint during Normal Open Time Zone',
    '17':  'Card plus Fingerprint Open',
    '18':  'First Card Normal Open (Press Fingerprint)',
    '19':  'First Card Normal Open (Card plus Fingerprint)',
    '20':  'Too Short Punch Interval',
    '21':  'Door Inactive Time Zone (Punch Card)',
    '22':  'Illegal Time Zone',
    '23':  'Access Denied',
    '24':  'Anti-Passback',
    '25':  'Interlock',
    '26':  'Multi-Card Authentication (Punching Card)',
    '27':  'Unregistered Card',
    '28':  'Opening Timeout',
    '29':  'Card Expired',
    '30':  'Password Error',
    '31':  'Too Short Fingerprint Pressing Interval',
    '32':  'Multi-Card Authentication (Press Fingerprint)',
    '33':  'Fingerprint Expired',
    '34':  'Unregistered Fingerprint',
    '35':  'Door Inactive Time Zone (Press Fingerprint)',
    '36':  'Door Inactive Time Zone (Exit Button)',
    '37':  'Failed to Close during Normal Open Time Zone',
    '101': 'Duress Password Open',
    '102': 'Opened Accidentally',
    '103': 'Duress Fingerprint Open',
    '200': 'Door Opened Correctly',
    '201': 'Door Closed Correctly',
    '202': 'Exit button Open',
    '203': 'Multi-Card Open (Card plus Fingerprint)',
    '204': 'Normal Open Time Zone Over',
    '205': 'Remote Normal Opening',
    '220': 'Auxiliary Input Disconnected',
    '221': 'Auxiliary Input Shorted',
    '255': 'Actually that obtain door status and alarm status',
}

ENTRY_EXIT_TYPES = {
    '0': 'Entry',
    '1': 'Exit',
    '2': 'None'
}

class ZK400:
    """ZKAccess C3-400"""
    relays = 8
    relays_def = (
        1, 2, 3, 4,
        1, 2, 3, 4
    )
    groups_def = (
        RelayGroup.aux,  RelayGroup.aux,  RelayGroup.aux,  RelayGroup.aux,
        RelayGroup.lock, RelayGroup.lock, RelayGroup.lock, RelayGroup.lock
    )

4

0 回答 0