Closed NguyenDucQuan12 closed 7 months ago
Hi,
Hmm, I see the listen
function isn't documented - I'll make a note to fix that. There is a sample in the example program but actually it's fairly straightforward:
set-listener
functionlisten
functione.g.:
import ipaddress
from uhppoted import uhppote
from pprint import pprint
def main():
controller = 405419896
host_addr = ipaddress.IPv4Address('192.168.1.100')
host_port = 60001
bind_addr = '0.0.0.0'
broadcast_addr = '255.255.255.255:60000'
listen_addr = '0.0.0.0:60001'
debug = True
try:
u = uhppote.Uhppote(bind_addr, broadcast_addr, listen_addr, debug)
set_listener(u,controller, host_addr, host_port)
listen(u)
except Exception as x:
print()
print(f'*** ERROR {x}')
print()
def set_listener(u, controller, address, port):
print('-- set-listener')
response = u.set_listener(controller, address, port)
print(' ', response)
print()
def listen(u):
print('-- listening for events')
u.listen(onEvent)
def onEvent(event):
if event != None:
pprint(event.__dict__, indent=2, width=1)
if __name__ == '__main__':
main()
If you edit that to set host_addr
to the IP address of your machine, run it and swipe a card you should get something like:
python3 main.py
-- set-listener
00000000 17 90 00 00 78 37 2a 18 c0 a8 01 64 61 ea 00 00
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000000 17 90 00 00 78 37 2a 18 01 00 00 00 00 00 00 00
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
SetListenerResponse(controller=405419896, ok=True)
-- listening for events
00000000 17 20 00 00 78 37 2a 18 46 00 00 00 01 00 03 01
00000010 a0 7a 99 00 20 24 04 02 19 14 07 12 00 00 00 00
00000020 00 00 00 00 00 19 14 07 00 00 00 00 00 00 00 00
00000030 00 00 00 24 04 02 00 00 00 00 00 00 00 00 00 00
{ 'controller': 405419896,
'door_1_button': False,
'door_1_open': False,
'door_2_button': False,
'door_2_open': False,
'door_3_button': False,
'door_3_open': False,
'door_4_button': False,
'door_4_open': False,
'event_access_granted': False,
'event_card': 10058400,
'event_direction': 1,
'event_door': 3,
'event_index': 70,
'event_reason': 18,
'event_timestamp': datetime.datetime(2024, 4, 2, 19, 14, 7),
'event_type': 1,
'inputs': 0,
'relays': 0,
'sequence_no': 0,
'special_info': 0,
'system_date': datetime.date(2024, 4, 2),
'system_error': 0,
'system_time': datetime.time(19, 14, 7)}
@uhppoted when I change controller and host_addr to my address, I swipe the card but it doesn't return any numbers. When I tried swiping the card with access control software, I still got the result (so I can eliminate the line connection problem). I don't know if I did any wrong steps.
I want to add more information to avoid unwanted situations: controller: acb-004 (s4a) card reader: idteck ip10 (connect wiegand 26) python: 3.11.8 I connect the controller to the switch and connect from the switch to the computer
Hmm - the fact that you got a valid reply back for the set-listener
command says your network setup is ok and the card reader is clearly working.
Are you by any chance running the access control software and the Python script at the same time? And do you possibly have an active breakpoint set on line 37?
I can set a breakpoint at line 37, I also turned off the access control software to try again, but still nothing appears when I swipe the card this is code:
import ipaddress
from uhppoted import uhppote
from pprint import pprint
def main():
controller = 423138650
host_addr = ipaddress.IPv4Address('169.254.184.123')
host_port = 60001
bind_addr = '0.0.0.0'
broadcast_addr = '255.255.255.255:60000'
listen_addr = '0.0.0.0:60001'
debug = True
try:
u = uhppote.Uhppote(bind_addr, broadcast_addr, listen_addr, debug)
set_listener(u,controller, host_addr, host_port)
listen(u)
except Exception as x:
print()
print(f'*** ERROR {x}')
print()
def set_listener(u, controller, address, port):
print('-- set-listener')
response = u.set_listener(controller, address, port)
print(' ', response)
print()
def listen(u):
print('-- listening for events')
u.listen(onEvent)
def onEvent(event):
if event != None:
pprint(event.__dict__, indent=2, width=1)
else:
print("nodata")
if __name__ == '__main__':
main()
Ok:
Can you perhaps post your network configuration? And just to confirm - you are running directly on the host machine with IP address 169.254.184.123 (and not e.g. in a VM or Docker container)?
Some other things you can try:
Change the listen_addr
to 169.254.184.123:60001 so that it is definitely binding to the correct IP.
You could also try downloading the CLI and running the following commands:
uhppote-cli --debug set-listener 423138650 169.254.184.123:60001
uhppote-cli --debug get-listener 423138650
uhppote-cli --debug listen
If that doesn't work then the next step is get Wireshark traces on the UDP packets to and from the controller.
(BTW it's late this side of the planet so I'll only be able to follow up tomorrow)
@uhppoted sorry, the ip address I passed in was the controller's ip, I changed it to the computer's ip address and it worked. Really sorry for my confusion, have a good night's sleep
Ah, yes! I was a bit puzzled .. I need to make a drawing or something that explains it better than words because a couple of people have done that.
Great! Very glad you're up and running :-).
Hi,
I've added the missing listen
API function to the README. The description is a bit brief but I've also added an event-listener example based on the code above which should hopefully make it clear for anybody else who runs into the same problem.
Going to close this one out - but feel free to reopen it if you need to :-).
@uhppoted Hello, I am dealing with a situation where after 2 minutes there is no card swipe event, then call the gc.collect function. However, it seems that the statement after else is never executed, I tested it. but no results were printed.
def onEvent(self,event):
# Nếu có sự kiện quẹt thẻ thì event nhận giá trị
if event:
self.time_start = time.time()
# 2 lệnh dưới sẽ in ra toàn bộ thông tin có trong thẻ
# pprint(event.__dict__, indent=2, width=1)
# print(event.event_card)
# Đây là sử dụng luồng, nếu số lượng luồng mở quá nhiều thì chương trình tự đóng, vì vậy dùng semaphore để giới hạn luồng được mở
# Không dùng join để đợi luồng này, bởi như vậy sẽ làm delay các quá trình còn lại, không giải quyết được vấn đề vượt CPU
if semaphore.acquire(blocking=False):
get_license_in_thread = threading.Thread(target=self.function, args=(event.event_card,))
get_license_in_thread.start()
# Chờ luồng kết thúc, sử dụng join()
# get_license_in_thread.join()
self.id_card = event.event_card
# Đây là không sử dụng luồng, nếu CPU>20% gây ra hiện tượng lag ( quẹt thẻ với tần suất 2s cho 1 lần quẹt)
# self.function(event.event_card)
# self.id_card = event.event_card
else:
current_time = time.time()
elapsed_time = current_time - self.time_start
print(current_time)
# Trong vòng 2 phút nếu không có sự kiện quẹt thẻ nào cả thì dọn các file rác và hiển thị quảng cáo
if elapsed_time >= 120:
print(current_time)
print(self.time_start)
gc.collect()
print("đã dọn bộ nhớ")
self.time_start = time.time()
Hi,
I'd be very surprised if event is ever None
because the onEvent handler is only called when an event is received - which means the else block is never going to be executed.
In my code I check for event == None
because it avoids a crash if (for example) there is a mistake in some other code - it is not an expected condition.
@uhppoted so is there any other way I can do the time calculation without the card swipe event? For example, how long has it been in the value of event = None
? I'm trying to call gc.collect()
every once in a while, because I'm multi-threaded so calling gc.collect()
too often causes unexpected problems.
Personally I would just start a separate thread in the main function to do garbage collection every 2 minutes.
Although TBH I'm a bit puzzled as to why you are doing garbage collection at all?
@uhppoted I am integrating object detection and OCR every time there is a card swipe event, however after each object detection +OCR, those 2 models do not automatically return the used resources, every time. It increased to 50MB of RAM again, after 300 card swipes it increased to 250MB of RAM. So I need to clean up the trash after there are no swipe events at all. To make sure that there is no situation where someone is swiping the card, gc.collect()
also collects garbage and causes the program to error. So I have to know when event = None
will allow me to collect the garbage
Huh! Very interesting!
In that situation I would typically have a separate thread to do garbage collection and something like a shared counter - when onEvent sees a card swipe it e.g. increments the counter. The thread would periodically wake up and decrement the counter and if the counter was zero then do a gc. There are lots of other ways to do it - but I'm afraid doing it in the else block isn't going to work because event == None
is only going to happen if there is a serious error in the controller (so basically never).
@uhppoted thank you so much
Pleasure! And good luck!
@uhppoted Can I limit the time to receive the id from the magnetic card, for example, after 2 seconds before I can swipe the card? Because if I intentionally swipe the card continuously (less than 1 second), it will cause an unexpected error, so I want to limit the time I can swipe the card to 2 seconds for each swipe.
What is the unexpected error you are getting?
@uhppoted Every time I swipe my card, I will open a new thread to perform tasks. However, if I swipe the card too quickly, many open threads will cause conflicts in the parameters in that thread. I don't have much experience. so I don't know how to handle it well
Oh .. ok, what you want to do is use a work queue:
To start with, the processing thread can just sleep in a loop and when it wakes up check the queue for a swipe event. Once you've got that working with just one thread you can get more sophisticated (e.g. wait for a signal/event) and/or use multiple processing threads. If you have e.g. 4 cores in your machine then you could run 4 processing threads.
You'll also need to use mutexes/semaphores to guard the queue but you can read up on that if you need to.
@uhppoted Thank you, I will try it immediately
Interestingly, if you use Python's queue.get()
you can do the gc.collection on timeout very easily!
(it's also threadsafe so you don't need to have external mutexes/semaphores).
hello, I'm currently using controller and I want to get card id every time I swipe the card using python, I wandered around, until I came across this project, it's amazing. There is almost no documentation on this issue, can you give me some instructions so that I can get the id every time I swipe the card through this controller. Thank you