Compare commits

..

2 Commits

Author SHA1 Message Date
Martin Quarda
5653972b8d creation of registrace.py application, upload time to website in StopWatch 2025-03-27 14:37:40 +01:00
Martin Quarda
c441dc7a32 fix spaces 2025-03-25 08:11:28 +01:00
16 changed files with 419 additions and 481 deletions

View File

@@ -30,8 +30,3 @@ for id in data_dict:
print(results) print(results)
dict(sorted(results.items(), key=lambda item: item[0])) dict(sorted(results.items(), key=lambda item: item[0]))
print(results) print(results)

View File

@@ -0,0 +1,10 @@
{
"url": "https://beta.alkator.cz/api/station/register",
"station_id": "1",
"login_url": "https://beta.alkator.cz/api/login",
"racers_url": "https://beta.alkator.cz/api/racers",
"card_register": "https://beta.alkator.cz/api/card/register",
"card_unregister": "https://beta.alkator.cz/api/card/card_unregister",
"login": "station_register@alkator.cz",
"password": "password_heslo"
}

View File

@@ -1,31 +1,75 @@
import gi import gi
import threading import threading
import time import time
import datetime
import collections
import usb.core import usb.core
import usb.util import usb.util
import requests import requests
import json import json
gi.require_version('Gtk', '4.0') gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, Gio, Gdk, GLib from gi.repository import Gtk, Gio, Gdk
DEBUG = False
if DEBUG == True:
index = 2
else:
index = 1
activeCards = [] activeCards = []
TIME = 60 TIME = 600
USB_IF = 0 # Interface USB_IF = 0 # Interface
USB_TIMEOUT = 5 # Timeout in ms USB_TIMEOUT = 5 # Timeout in ms
USB_VENDOR = 0xffff # Vendor-ID: USB_VENDOR = 0xffff # Vendor-ID:
USB_PRODUCT = 0x0035 # Product-ID USB_PRODUCT = 0x0035 # Product-ID
with open('people.json', 'r') as f: db = {}
db = json.load(f)
queue_to_send = []
with open('config.json', 'r') as f:
config = json.load(f)
session = requests.Session()
session.post(config['login_url'], {'email':config['login'], 'password': config['password']})
def refreshDb():
global db
resp = session.get(config['racers_url'])
if resp.status_code == 200:
json = resp.json()
db = {}
for racer in json:
if racer["card_id"]:
db[racer["card_id"]] = racer
def refreshDbEvery3mins():
while True:
refreshDb()
time.sleep(3 * 60)
Thread(target=refreshDbEvery3mins).start()
def sendQueueToSend():
global queue_to_send
while True:
if len(queue_to_send) > 0:
to_send = queue_to_send.pop()
response = session.post(config['url'],
to_send, 'application/json'
)
if response.status_code != 200:
if response.status_code == 400:
continue
queue_to_send.append(to_send) #try again later
time.sleep(1)
else:
time.sleep(1)
Thread(target=sendQueueToSend).start()
class UsbCardReader(): class UsbCardReader():
def __init__(self, **kargs): def __init__(self, **kargs):
@@ -59,17 +103,17 @@ class UsbCardReader():
receivedNumber = 10 * receivedNumber + receivedDigit receivedNumber = 10 * receivedNumber + receivedDigit
if (( control[0] == 0 )) & (( control[2] == 40 )) & (( not receivedNumber == 0 )): if (( control[0] == 0 )) & (( control[2] == 40 )) & (( not receivedNumber == 0 )):
try: if receivedNumber not in db:
with open('people.json', 'r') as f: refreshDb()
db = json.load(f) if receivedNumber in db:
for i in db: if receivedNumber not in activeCards:
if db[i] == receivedNumber: activeCards.append(receivedNumber)
if i not in activeCards: win.arb(db[receivedNumber])
activeCards.append(i) print('Card is active now')
GLib.idle_add(win.arb, i) else:
else: print('Card is already active')
print("Card is active now") else:
except Exception as e: print(e) print(f'Card {receivedNumber} not found in db')
receivedNumber = 0 receivedNumber = 0
except KeyboardInterrupt: except KeyboardInterrupt:
@@ -80,9 +124,9 @@ class UsbCardReader():
time.sleep(0.001) time.sleep(0.001)
class GridRow(): class GridRow():
def __init__(self, parent, runner, index): def __init__(self, parent, racer, index):
self.id = runner global queue_to_send
self.index = index self.id = racer['starting_number']
self.parent = parent self.parent = parent
self.grid = Gtk.Grid() self.grid = Gtk.Grid()
@@ -92,7 +136,7 @@ class GridRow():
else: else:
self.grid.set_name("darkgrid") self.grid.set_name("darkgrid")
self.runid = Gtk.Label(label=str(runner), name="gridlabel") self.runid = Gtk.Label(label=str(racer["starting_number"]), name="gridlabel")
self.runid.set_justify(2) self.runid.set_justify(2)
self.runid.set_width_chars(10) self.runid.set_width_chars(10)
@@ -107,6 +151,12 @@ class GridRow():
countdown=threading.Thread(target=self.updateTime) countdown=threading.Thread(target=self.updateTime)
countdown.start() countdown.start()
queue_to_send.append({
'card_id': racer['card_id'],
'station_id': config['station_id'],
'time': datetime.datetime.now().strftime('%d.%m.%Y %H:%M:%S.%f')
})
def printIndex(self, button): def printIndex(self, button):
print(self.index) print(self.index)
@@ -119,16 +169,16 @@ class GridRow():
else: else:
mins, secs = divmod(t, 60) mins, secs = divmod(t, 60)
timer = '{:02d}:{:02d}'.format(mins, secs) timer = '{:02d}:{:02d}'.format(mins, secs)
GLib.idle_add(self.runb.set_label, timer) self.runb.set_label(timer)
time.sleep(1) time.sleep(1)
t -= 1 t -= 1
if t == 10: if t == 10:
if self.grid.get_name() == "lightgrid": if self.grid.get_name() == "lightgrid":
GLib.idle_add(self.grid.set_name, "lredgrid") self.grid.set_name("lredgrid")
else: else:
GLib.idle_add(self.grid.set_name, "dredgrid") self.grid.set_name("dredgrid")
GLib.idle_add(GridWindow.remRow, self.parent) GridWindow.remRow(self.parent)
class GridWindow(Gtk.ApplicationWindow): class GridWindow(Gtk.ApplicationWindow):
def __init__(self, **kargs): def __init__(self, **kargs):
@@ -137,13 +187,6 @@ class GridWindow(Gtk.ApplicationWindow):
css_provider = Gtk.CssProvider() css_provider = Gtk.CssProvider()
css_provider.load_from_file(Gio.File.new_for_path("style.css")) css_provider.load_from_file(Gio.File.new_for_path("style.css"))
Gtk.StyleContext.add_provider_for_display(Gdk.Display.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION) Gtk.StyleContext.add_provider_for_display(Gdk.Display.get_default(), css_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
self.set_default_size(640, 480)
button1 = Gtk.Button(label='addrow')
button2 = Gtk.Button(label='rmrow')
button1.connect("clicked", self.arb)
button2.connect("clicked", self.rrb)
runlabel = Gtk.Label(label="ID", name="gridlabel") runlabel = Gtk.Label(label="ID", name="gridlabel")
runlabel.set_justify(2) runlabel.set_justify(2)
@@ -153,24 +196,15 @@ class GridWindow(Gtk.ApplicationWindow):
self.runners = [] self.runners = []
self.grid = Gtk.Grid() self.grid = Gtk.Grid()
if DEBUG == True: self.grid.attach(runlabel, 0, 0, 1, 1)
self.grid.attach(button1, 0, 0, 1, 1) self.grid.attach(cntlabel, 1, 0, 2, 1)
self.grid.attach(button2, 1, 0, 2, 1)
self.grid.attach(runlabel, 0, 1, 1, 1)
self.grid.attach(cntlabel, 1, 1, 2, 1)
else:
self.grid.attach(runlabel, 0, 0, 1, 1)
self.grid.attach(cntlabel, 1, 0, 2, 1)
self.set_child(self.grid) self.set_child(self.grid)
def arb(self, personId): def arb(self, racer):
global index self.runners.append(GridRow(self, racer, len(activeCards)))
self.runners.append(GridRow(self, personId, index))
index += 1
def rrb(self, button): def rrb(self, button):
global index
self.remRow() self.remRow()
def addRow(self, runner, index): def addRow(self, runner, index):
@@ -181,10 +215,9 @@ class GridWindow(Gtk.ApplicationWindow):
self.grid.attach(runb, 1, index, 1, 1) self.grid.attach(runb, 1, index, 1, 1)
def remRow(self): def remRow(self):
global index, activeCards global activeCards
if index > 1: if len(activeCards) > 0:
self.grid.remove_row(1) self.grid.remove_row(1)
index -= 1
del activeCards[0] del activeCards[0]

View File

@@ -1,23 +0,0 @@
import operator
import json
db=""
res={}
with open('times.json', 'r') as f:
db = json.load(f)
for i in db:
try:
res[i] = db[i]["duration"]
print(i, db[i]["duration"])
except:
print(i)
pass
#print(res)
order = dict(sorted(res.items(), key=lambda item: item[1]))
with open("results.json", 'a') as f:
f.write(json.dumps(order, indent = 4))

View File

@@ -1,102 +1,4 @@
{ {
"1": 1114418469, "1": 3619716179,
"2": 1111554085, "2": 3620062547
"3": 1112605381,
"4": 1362080126,
"5": 1632101230,
"6": 1114533941,
"7": 1364901054,
"8": 1364587710,
"9": 1364867822,
"10": 1364554558,
"11": 1364968750,
"12": 1111614357,
"13": 1362569198,
"14": 1364867662,
"15": 1112618821,
"16": 1364967150,
"17": 1364592718,
"18": 1364487310,
"19": 458336708,
"20": 1111590293,
"21": 1114448773,
"22": 1364550814,
"23": 1112421509,
"24": 1364529422,
"25": 1364916590,
"26": 455988804,
"27": 1631963022,
"28": 1114508533,
"29": 1364590606,
"30": 1364796894,
"31": 1112489029,
"32": 1114588261,
"33": 1111733589,
"34": 1112469509,
"35": 1632521678,
"36": 1631957710,
"37": 1111682853,
"38": 1111882197,
"39": 1631960974,
"40": 1362260606,
"41": 1364521806,
"42": 1364489406,
"43": 1361969902,
"44": 1364581838,
"45": 1364520526,
"46": 1361806574,
"47": 1364581310,
"48": 1364551150,
"49": 1364916158,
"50": 1364529662,
"51": 1632026766,
"52": 1364588798,
"53": 1631955550,
"54": 1631972606,
"55": 1364797086,
"56": 1364627198,
"57": 1364556446,
"58": 1632070414,
"59": 1631951758,
"60": 1364794654,
"61": 1632101166,
"62": 1361810574,
"63": 1114573589,
"64": 1361967886,
"65": 1632544222,
"66": 1111582085,
"67": 1362569438,
"68": 1364593198,
"69": 1364761406,
"70": 1631927918,
"71": 1364544414,
"72": 1362264958,
"73": 1364767006,
"74": 1364590110,
"75": 1362082334,
"76": 1364799166,
"77": 1632028398,
"78": 1361970078,
"79": 1364485118,
"80": 1364490846,
"81": 1632150846,
"82": 1362569342,
"83": 1362599998,
"84": 1632523854,
"85": 1364765134,
"86": 1631952062,
"87": 1364559822,
"88": 1364783854,
"89": 1362081950,
"90": 1111644021,
"91": 1631959326,
"92": 1364901422,
"93": 1632100830,
"94": 1111707429,
"95": 1632026702,
"96": 1362569022,
"97": 1114560181,
"98": 1364588510,
"99": 1364785486,
"100": 1361969950
} }

View File

@@ -0,0 +1,134 @@
import sys
import datetime
import requests
import json
import usb.core
import usb.util
from PyQt6 import QtWidgets, uic, QtGui
app = QtWidgets.QApplication(sys.argv)
TIME = 600
USB_IF = 0 # Interface
USB_TIMEOUT = 5 # Timeout in ms
USB_VENDOR = 0xffff # Vendor-ID:
USB_PRODUCT = 0x0035 # Product-ID
with open('config.json', 'r') as f:
config = json.load(f)
session = requests.Session()
session.post(config['login_url'], {'email':config['login'], 'password': config['password']})
last_card = 1111
last_time = datetime.datetime.now()
response = session.get(config['racers_url'])
racers = response.json()
def register_racer():
card_id = last_card
index = window.racers.currentIndex()
racer_id = int(index.data().split(' ')[-1])
try:
starting_number = int(window.starting_number.text())
except Exception:
raise
response = session.post(config['card_register'], json={'racer_id': racer_id, 'starting_number': starting_number, 'card_id': last_card})
if response.status_code != 200:
raise Exception(response.status_code, response.content)
racer = list(filter(lambda x: x['racer_id'] == racer_id, racers))[0]
racer['card_id'] = card_id
racer['starting_number'] = starting_number
updateRacers()
def unregister_racer():
card_id = last_card
time = last_time
response = session.post(config['url'], json={'card_id': card_id, 'time': time.strftime('%d.%m.%Y %H:%M:%S.%f'), 'station_id': config['station_id']})
window = uic.loadUi("registrace.ui")
window.register_racer.clicked.connect(register_racer)
window.unregister_racer.clicked.connect(unregister_racer)
window.show()
model = QtGui.QStandardItemModel()
window.racers.setModel(model)
def updateRacers():
model.clear()
for racer in racers:
if racer['starting_number'] or racer['card_id']:
continue
item = QtGui.QStandardItem(f"{racer['last_name']} {racer['first_name']} {racer['date_of_birth']} {racer['racer_id']}")
model.appendRow(item)
updateRacers()
def updateLastCard(card_id):
window.lastCard.setText(str(card_id))
class UsbCardReader():
def __init__(self, **kargs):
# Find the HID device by vendor/product ID
self.dev = usb.core.find(idVendor=USB_VENDOR, idProduct=USB_PRODUCT)
# Get and store the endpoint
self.endpoint = self.dev[0][(0,0)][0]
if self.dev.is_kernel_driver_active(USB_IF) is True:
self.dev.detach_kernel_driver(USB_IF)
# Claim the device
usb.util.claim_interface(self.dev, USB_IF)
self.receivedNumber = 0
cardread=threading.Thread(target=self.read)
cardread.start()
def read(self):
global last_card, last_time
print("Waiting for card")
receivedNumber = 0
while True:
control = None
try:
control = self.dev.read(self.endpoint.bEndpointAddress, self.endpoint.wMaxPacketSize, USB_TIMEOUT)
if (control[2] != 40) & (control[2] != 0):
receivedDigit = control[2] - 29
if receivedDigit == 10:
receivedDigit = 0
receivedNumber = 10 * receivedNumber + receivedDigit
if (( control[0] == 0 )) & (( control[2] == 40 )) & (( not receivedNumber == 0 )):
updateLastCard(receivedNumber)
if last_card != receivedNumber:
last_time = datetime.datetime.now()
last_card = receivedNumber
receivedNumber = 0
except KeyboardInterrupt:
exit()
except:
pass
time.sleep(0.001)
UsbCardReader()
app.exec()

View File

@@ -0,0 +1,71 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Frame</class>
<widget class="QFrame" name="Frame">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>315</width>
<height>289</height>
</rect>
</property>
<property name="windowTitle">
<string>Registrace závodníků</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="5" column="0">
<widget class="QLineEdit" name="lastCard"/>
</item>
<item row="0" column="0">
<widget class="QPushButton" name="register_racer">
<property name="text">
<string>Registrovat</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QPushButton" name="unregister_racer">
<property name="text">
<string>Dokončit</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLineEdit" name="starting_number"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label">
<property name="text">
<string>startovní číslo</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_2">
<property name="text">
<string>číslo karty</string>
</property>
</widget>
</item>
<item row="6" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1" rowspan="7">
<widget class="QListView" name="racers"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -1,34 +0,0 @@
{
"2": "0:35:59.818971",
"29": "1:10:52.076408",
"14": "1:11:35.670162",
"9": "1:14:40",
"10": "1:16:02.174205",
"12": "1:18:12.521345",
"26": "1:21:24.962008",
"8": "1:23:45.241021",
"5": "1:24:33.080748",
"3": "1:25:36.486060",
"25": "1:26:57.409779",
"27": "1:32:49.493213",
"18": "1:35:04.610546",
"6": "1:35:28.914085",
"21": "1:35:29.494112",
"28": "1:37:56.900763",
"13": "1:39:20.394593",
"17": "1:39:59.664271",
"4": "1:40:15.602185",
"15": "1:41:16.795669",
"20": "1:43:29.166855",
"16": "1:48:28.014745",
"19": "1:48:37.692711",
"30": "1:48:51.712639",
"11": "1:48:56.350571",
"22": "1:49:04.450512",
"31": "2:05:10.107744",
"24": "2:05:33.883454",
"7": "2:05:42.955540",
"32": "2:06:17.053222",
"23": "2:11:50.391043",
"1": "2:24:50.507501"
}

View File

@@ -1,160 +1,12 @@
{ {
"1": { "1": {
"start": "31/05/2025, 10:00:08", "start": "25/02/2025, 18:06:16",
"end": "31/05/2025, 12:24:58", "end": "25/02/2025, 18:06:31",
"duration": "2:24:50.507501" "duration": "0:00:14.553644"
}, },
"2": { "2": {
"start": "31/05/2025, 10:05:37", "start": "25/02/2025, 18:15:08",
"end": "31/05/2025, 10:41:37", "end": "25/02/2025, 18:15:27",
"duration": "0:35:59.818971" "duration": "0:00:19.543765"
},
"3": {
"start": "31/05/2025, 10:10:09",
"end": "31/05/2025, 11:35:45",
"duration": "1:25:36.486060"
},
"4": {
"start": "31/05/2025, 10:15:14",
"end": "31/05/2025, 11:55:30",
"duration": "1:40:15.602185"
},
"5": {
"start": "31/05/2025, 10:20:08",
"end": "31/05/2025, 11:44:41",
"duration": "1:24:33.080748"
},
"6": {
"start": "31/05/2025, 10:25:01",
"end": "31/05/2025, 12:00:30",
"duration": "1:35:28.914085"
},
"7": {
"start": "31/05/2025, 10:30:01",
"end": "31/05/2025, 12:35:44",
"duration": "2:05:42.955540"
},
"8": {
"start": "31/05/2025, 10:35:05",
"end": "31/05/2025, 11:58:50",
"duration": "1:23:45.241021"
},
"9": {
"start": "31/05/2025, 10:39:57"
},
"10": {
"start": "31/05/2025, 10:42:01",
"end": "31/05/2025, 11:58:03",
"duration": "1:16:02.174205"
},
"11": {
"start": "31/05/2025, 10:45:03",
"end": "31/05/2025, 12:33:59",
"duration": "1:48:56.350571"
},
"12": {
"start": "31/05/2025, 10:49:58",
"end": "31/05/2025, 12:08:10",
"duration": "1:18:12.521345"
},
"13": {
"start": "31/05/2025, 10:55:01",
"end": "31/05/2025, 12:34:21",
"duration": "1:39:20.394593"
},
"14": {
"start": "31/05/2025, 10:59:57",
"end": "31/05/2025, 12:11:33",
"duration": "1:11:35.670162"
},
"15": {
"start": "31/05/2025, 11:05:09",
"end": "31/05/2025, 12:46:25",
"duration": "1:41:16.795669"
},
"16": {
"start": "31/05/2025, 11:10:01",
"end": "31/05/2025, 12:58:29",
"duration": "1:48:28.014745"
},
"17": {
"start": "31/05/2025, 11:15:00",
"end": "31/05/2025, 12:55:00",
"duration": "1:39:59.664271"
},
"18": {
"start": "31/05/2025, 11:20:01",
"end": "31/05/2025, 12:55:05",
"duration": "1:35:04.610546"
},
"19": {
"start": "31/05/2025, 11:25:00",
"end": "31/05/2025, 13:13:38",
"duration": "1:48:37.692711"
},
"20": {
"start": "31/05/2025, 11:29:58",
"end": "31/05/2025, 13:13:27",
"duration": "1:43:29.166855"
},
"21": {
"start": "31/05/2025, 11:35:30",
"end": "31/05/2025, 13:11:00",
"duration": "1:35:29.494112"
},
"22": {
"start": "31/05/2025, 11:40:02",
"end": "31/05/2025, 13:29:06",
"duration": "1:49:04.450512"
},
"23": {
"start": "31/05/2025, 11:44:59",
"end": "31/05/2025, 13:56:49",
"duration": "2:11:50.391043"
},
"24": {
"start": "31/05/2025, 11:50:45",
"end": "31/05/2025, 13:56:19",
"duration": "2:05:33.883454"
},
"25": {
"start": "31/05/2025, 11:55:04",
"end": "31/05/2025, 13:22:02",
"duration": "1:26:57.409779"
},
"26": {
"start": "31/05/2025, 12:00:00",
"end": "31/05/2025, 13:21:24",
"duration": "1:21:24.962008"
},
"27": {
"start": "31/05/2025, 12:05:01",
"end": "31/05/2025, 13:37:51",
"duration": "1:32:49.493213"
},
"28": {
"start": "31/05/2025, 12:10:03",
"end": "31/05/2025, 13:48:00",
"duration": "1:37:56.900763"
},
"29": {
"start": "31/05/2025, 12:14:58",
"end": "31/05/2025, 13:25:50",
"duration": "1:10:52.076408"
},
"30": {
"start": "31/05/2025, 12:20:02",
"end": "31/05/2025, 14:08:54",
"duration": "1:48:51.712639"
},
"31": {
"start": "31/05/2025, 12:50:10",
"end": "31/05/2025, 14:55:20",
"duration": "2:05:10.107744"
},
"32": {
"start": "31/05/2025, 12:50:13",
"end": "31/05/2025, 14:56:30",
"duration": "2:06:17.053222"
} }
} }

View File

@@ -90,7 +90,6 @@ def main():
elif rw == '': elif rw == '':
s.write('r\r'.encode()) s.write('r\r'.encode())
read(s) read(s)
else: else:
print('Invalid option') print('Invalid option')

View File

@@ -406,4 +406,3 @@ class PN532:
_COMMAND_INDATAEXCHANGE, params=params, response_length=1 _COMMAND_INDATAEXCHANGE, params=params, response_length=1
) )
return response[0] == 0x00 return response[0] == 0x00