commit a80c03a27d76de8c5891b527aaf86d672b6d7afd Author: Юрий Черненко Date: Wed Nov 5 18:29:49 2025 +0300 first commit diff --git a/RPL/main.py b/RPL/main.py new file mode 100644 index 0000000..953727a --- /dev/null +++ b/RPL/main.py @@ -0,0 +1,163 @@ +import socket +import requests + + +def send_data(value): + url = "http://127.0.0.1:8088/API/" + par = "SetText" + if 'проверка' in value: + input = 34 + else: + input = 35 + if "-" in value: + params = { + "Function": par, + "Input": input, + "SelectedName": "СТрока1.Text", + "Value": value.split("-")[0].strip(), + } + requests.get(url, params=params) + params = { + "Function": par, + "Input": input, + "SelectedName": "Строка2.Text", + "Value": value.split("-")[1].strip(), + } + requests.get(url, params=params) + + +VOR = "VOR3" + +list_code = { + "101": "Приветствие", + "102": "Инфо", + "103": "Игра проходит без системы определения офсайдных линий", + "104": "Игра проходит без системы VAR", + "105": "Проверка", + "106": "проверка - Офсайд", + "107": "проверка - Возможно, офсайд", + "108": "проверка - Игра рукой", + "109": "проверка - Фол в атаке", + "110": "проверка - Симуляция", + "111": "Игра проходит с системой VAR", + "112": "Игра проходит с ограниченными техническими возможностями", + "113": "Объявление решения", + "114": "Неисправность системы объявления решений судьи", + "115": "Не используется система объявления решений судьи", + "116": "Решение подтверждено - офсайд", + "117": "Нет офсайда", + "118": "Возможно игра рукой в атаке", + "119": "проверка - Игра рукой в атаке", + "201": "проверка - Гол", + "202": "Решение подтверждено - гол", + "203": "Решение подтверждено - гол, нет офсайда", + "204": "Решение подтверждено - гол, нет фола", + "205": "Решение подтверждено - гол, нет игры рукой", + "206": "Решение подтверждено - гол, мяч в игре", + "207": "Решение подтверждено - гол, симуляция", + "208": "Решение подтверждено - гол, мяч пересек линию ворот", + "209": "Решение изменено - нет гола, офсайд", + "210": "Решение изменено - нет гола, фол", + "211": "Решение изменено - нет гола, игра рукой", + "212": "Решение изменено - нет гола, мяч не в игре", + "213": "Решение изменено - нет гола, мяч не пересек линию ворот", + "301": "проверка - Возможно, гол", + "302": "Решение подтверждено - нет гола", + "303": "Решение подтверждено - нет гола, офсайд", + "304": "Решение подтверждено - нет гола, фол", + "305": "Решение подтверждено - нет гола, игра рукой", + "306": "Решение подтверждено - нет гола, мяч не в игре", + "307": "Решение подтверждено - нет гола, мяч не пересек линию ворот", + "308": "Решение изменено - гол", + "309": "Решение изменено - гол, нет офсайда", + "310": "Решение изменено - гол, нет фола", + "311": "Решение изменено - гол, нет игры рукой", + "312": "Решение изменено - гол, мяч в игре", + "313": "Решение изменено - гол, симуляция", + "314": "Решение изменено - гол, мяч пересек линию ворот", + "401": "проверка - Пенальти", + "402": "Решение подтверждено - пенальти", + "403": "Решение подтверждено - пенальти, фол", + "404": "Решение подтверждено - пенальти, игра рукой", + "405": "Решение подтверждено - пенальти, фол в штрафной", + "406": "Решение подтверждено - пенальти, игра рукой в штрафной", + "407": "Решение изменено - нет пенальти, нет фола", + "408": "Решение изменено - нет пенальти, нет игры рукой", + "409": "Решение изменено - нет пенальти, фол за штрафной", + "410": "Решение изменено - нет пенальти, офсайд", + "411": "Решение изменено - нет пенальти, фол в атаке", + "412": "Решение изменено - нет пенальти, игра рукой в атаке", + "413": "Решение изменено - нет пенальти, мяч не в игре", + "414": "Решение изменено - нет пенальти, симуляция", + "501": "проверка - Возможно, пенальти", + "502": "Решение подтверждено - нет пенальти", + "503": "Решение подтверждено - нет пенальти, нет фола", + "504": "Решение подтверждено - нет пенальти, нет игры рукой", + "505": "Решение подтверждено - нет пенальти, фол за штрафной", + "506": "Решение подтверждено - нет пенальти, офсайд", + "507": "Решение подтверждено - нет пенальти, фол в атаке", + "508": "Решение подтверждено - нет пенальти, игра рукой в атаке", + "509": "Решение подтверждено - нет пенальти, мяч не в игре", + "510": "Решение подтверждено - нет пенальти, симуляция", + "511": "Решение изменено - пенальти", + "512": "Решение изменено - пенальти, фол", + "513": "Решение изменено - пенальти, игра рукой", + "514": "Решение изменено - пенальти, фол в штрафной", + "515": "Решение изменено - пенальти, игра рукой в штрафной", + "516": "Решение изменено – пенальти, нет симуляции", + "601": "проверка - Красная карточка", + "602": "Решение подтверждено - красная карточка", + "603": "Решение изменено - жёлтая карточка", + "604": "Решение изменено - нет карточки", + "701": "проверка - Возможно, красная карточка", + "702": "Решение подтверждено - нет красной карточки", + "703": "Решение изменено - красная карточка", + "704": "Решение изменено - жёлтая карточка", + "801": "проверка - Идентификация игрока", + "802": "Ошибочная идентификация игрока", +} + + +HOST = '127.0.0.1' # Принимаем соединения со всех интерфейсов +PORT = 60000 # Порт, который будем слушать + + +def start_tcp_server(): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server_socket: + server_socket.bind((HOST, PORT)) + server_socket.listen(5) + print(f"Сервер запущен на {HOST}:{PORT}") + + while True: + client_socket, addr = server_socket.accept() + with client_socket: + print(f"Клиент подключился: {addr}") + while True: + data = client_socket.recv(1024) + if not data: + break + + try: + decoded = data.decode('utf-8') + print(f"Получено: {decoded}") + send_data(list_code[decoded.split("/")[2]]) + + # parts = decoded.split(", ") + # if len(parts) != 2: + # print("Неверный формат сообщения") + # continue + + # sender, code = parts + # if sender == VOR and code in list_code: + # send_data(list_code[code]) + # else: + # print("Неверный код или отправитель") + + except Exception as e: + print(f"Ошибка обработки данных: {e}") + + print(f"Отключение клиента: {addr}") + + +if __name__ == "__main__": + start_tcp_server() diff --git a/data_sender.py b/data_sender.py new file mode 100644 index 0000000..9e00fe9 --- /dev/null +++ b/data_sender.py @@ -0,0 +1,11 @@ +import requests + + +def send_data_to_ips(data, ip_list): + for ip in ip_list: + try: + url = f"{ip}/API/" + response = requests.post(url, json=data) + print(f"Data sent to {ip}: {response.status_code}") + except Exception as e: + print(f"Error sending data to {ip}: {e}") diff --git a/divs/jsonserver.py b/divs/jsonserver.py new file mode 100644 index 0000000..4492b47 --- /dev/null +++ b/divs/jsonserver.py @@ -0,0 +1,405 @@ +import json +from http.server import BaseHTTPRequestHandler, HTTPServer +import threading +import requests +import io +import asyncore + +jsonserver_hostname = "localhost" +jsonserver_port = 8800 + +#refserver_hostname = "192.168.68.150" +#refserver_port = 26700 +refserver_hostname = "192.168.190.78" +refserver_port = 4001 + +vMixAPI_address = 'http://localhost:8088/API/' +vMixAPI_TimerInputID = 'TIMER' +vMixAPI_TimerTextField = 'Clock .Text' +vMixAPI_Timer24InputID = 'TIMER' +vMixAPI_Timer24TextField = 'Title Text.Text' +vMixAPI_ColorPlace = '#C7A2E399' +vMixAPI_ColorNone = "#00000000" + +game_filename = 'game.json' +homeplayers_filename = 'homeplayers.json' +guestplayers_filename = 'guestplayers.json' + +Game = { + 'type': '', + 'home_name': '', + 'guest_name': '' +} + +GameHandFutsal = { + 'timer': '', + 'home_fouls': '', + 'guest_fouls': '', + 'home_points': '', + 'guest_points': '', + 'period': '', + 'home_penalties': '', + 'guest_penalties': '', + 'home_timeouts': '', + 'guest_timeouts': '', + 'horn': '', + 'timer_status': '', + 'home_penalty1_player': '', + 'home_penalty2_player': '', + 'home_penalty3_player': '', + 'home_penalty1_timer': '', + 'home_penalty2_timer': '', + 'home_penalty3_timer': '', + 'guest_penalty1_player': '', + 'guest_penalty2_player': '', + 'guest_penalty3_player': '', + 'guest_penalty1_timer': '', + 'guest_penalty2_timer': '', + 'guest_penalty3_timer': '' +} + +GameBasketball = { + 'ball_pos':'', + 'timer':'', + 'home_points':'', + 'guest_points':'', + 'period':'', + 'home_fouls':'', + 'guest_fouls':'', + 'home_timeouts':'', + 'guest_timeouts':'', + 'horn':'', + 'timer_status':'', + 'timeout_timer':'', + 'timer24':'', + 'horn24':'', + 'timer24_status':'', + 'timer24_display':'', +} + +HomePlayers = [{ + 'number': '', + 'name': '', + 'points': '', + 'fouls': '' +} for i in range(0, 16)] + +GuestPlayers = [{ + 'number': '', + 'name': '', + 'points': '', + 'fouls': '' +} for i in range(0, 16)] + + +def TimerSet(time): + #requests.get('{api_address}?Function=SetText&Input={input}&SelectedName={field}&Value={value}'.format(api_address=vMixAPI_address, input=vMixAPI_TimerInputID, field=vMixAPI_TimerTextField, value=time)) + pass + +def Timer24Set(time): + #requests.get('{api_address}?Function=SetText&Input={input}&SelectedName={field}&Value={value}'.format(api_address=vMixAPI_address, input=vMixAPI_TimerInputID, field=vMixAPI_TimerTextField, value=time)) + pass + + +def dc(v): + if isinstance(v, int): + return bytes([v]).decode() + else: + return bytes(v).decode() + + +def pn_ball_pos(v): + return 'home' if v == 0x31 else ('guset' if v == 0x32 else '') + +def pn_timer(v): + return dc(v[0:2]) + ':' + dc(v[2:4]) + +def pn_points(v): + return dc(v.strip()) + +def pn_period(v): + return dc(v) if v != 0x30 else 'O' + +def pn_teamfouls(v): + return dc(v) if v != 0x52 else 'red' + +def pn_timeouts(v): + return dc(v) + +def pn_horn(v): + return 1 if v == 0x31 else 0 + +def pn_startstop(v): + return 1 if v == 0x30 else 0 + +def pn_timertimeout(v): + return dc(v[0]) + ':' + dc(v[1:3]) + +def pn_timer24(v): + return dc(v) if 0x30 <= v[1] and v[1] <= 0x39 else dc(v[0]) + '.' + dc(v[1] - 0x10) + +def pn_display24(v): + return 1 if v != 0x30 else 0 + +def pn_playernumber(v): + return dc(v) + +def pn_playerfouls(v): + return dc(v) + +def pn_penalties(v): + return dc(v) + +def pn_name(v): + return v.decode('utf-16') + +def parce(pkg): + global GameHandFutsal, GameBasketball, HomePlayers, GuestPlayers + + if len(pkg) < 54: + print('Error: pkg too short') + return + if pkg[0] != 0xf8 or pkg[53] != 0x0d: + print('Error: Frame uncorrect') + return + + sport_code = pkg[1] + + if sport_code == 0x33 or sport_code == 0x37 or sport_code == 0x38: + GameBasketball.update({ + 'timer': pn_timer(pkg[4:8]), + 'horn': pn_horn(pkg[19]), + 'timer_status': pn_startstop(pkg[20]), + 'timer24': pn_timer24(pkg[48:50]), + 'horn24': pn_horn(pkg[50]), + 'timer24_status': pn_startstop(pkg[51]), + 'timer24_display': pn_display24(pkg[52]) + }) + + if GameBasketball['timer24_display'] == 0: + GameBasketball['timer24'] = ' ' + + if sport_code == 0x33: # BASKETBALL with individual fouls + Game['type'] = 'Basketball' + + GameBasketball.update({ + 'ball_pos': pn_ball_pos(pkg[3]), + 'home_points': pn_points(pkg[8:11]), + 'guest_points': pn_points(pkg[11:14]), + 'period': pn_period(pkg[14]), + 'home_fouls': pn_teamfouls(pkg[15]), + 'guest_fouls': pn_teamfouls(pkg[16]), + 'home_timeouts': pn_timeouts(pkg[17]), + 'guest_timeouts': pn_timeouts(pkg[18]), + 'timeout_timer': pn_timertimeout(bytes([pkg[21]]) + pkg[46:48]), + }) + + for i in range(0, 12): + HomePlayers[i]['fouls'] = pn_playerfouls(pkg[22 + i]) + for i in range(0, 12): + GuestPlayers[i]['fouls'] = pn_playerfouls(pkg[34 + i]) + + TimerSet(GameBasketball['timer']) + Timer24Set(GameBasketball['timer24']) + + + elif sport_code == 0x35: # HANDBALL/FUTSAL + Game['type'] = 'HandFutsal' + + GameHandFutsal.update({ + 'timer': pn_timer(pkg[4:8]), + 'home_fouls': pn_teamfouls(pkg[8]), + 'home_points': pn_points(pkg[9:11]), + 'guest_fouls': pn_teamfouls(pkg[11]), + 'guest_points': pn_points(pkg[12:14]), + 'period': pn_period(pkg[14]), + 'home_penalties': pn_penalties(pkg[15]), + 'guest_penalties': pn_penalties(pkg[16]), + 'home_timeouts': pn_timeouts(pkg[17]), + 'guest_timeouts': pn_timeouts(pkg[18]), + 'horn': pn_horn(pkg[19]), + 'timer_status': pn_startstop(pkg[20]), + 'home_penalty1_player': pn_playernumber(pkg[22:24]), + 'home_penalty2_player': pn_playernumber(pkg[27:29]), + 'home_penalty3_player': pn_playernumber(pkg[32:34]), + 'home_penalty1_timer': pn_playerfouls(pkg[24:27]), + 'home_penalty2_timer': pn_playerfouls(pkg[29:32]), + 'home_penalty3_timer': pn_playerfouls(pkg[34:37]), + 'guest_penalty1_player': pn_playernumber(pkg[37:39]), + 'guest_penalty2_player': pn_playernumber(pkg[42:44]), + 'guest_penalty3_player': pn_playernumber(pkg[47:49]), + 'guest_penalty1_timer': pn_playerfouls(pkg[39:42]), + 'guest_penalty2_timer': pn_playerfouls(pkg[44:47]), + 'guest_penalty3_timer': pn_playerfouls(pkg[49:52]) + }) + + elif sport_code == 0x36: # VOLLEYBALL + pass + + elif sport_code == 0x37: # Individual points - GUEST BASKET/HAND/HOCKEY/FUTSAL + for i in range(0, 13): + GuestPlayers[i]['points'] = pn_points(pkg[22 + 2*i : 24 + 2*i]) + for i in range(13, 16): + GuestPlayers[i]['points'] = pn_points(pkg[11 + 2*i : 13 + 2*i]) + print(GuestPlayers) + + elif sport_code == 0x38: # Individual points - HOME BASKET/HAND/HOCKEY/FUTSAL + for i in range(0, 13): + HomePlayers[i]['points'] = pn_points(pkg[22 + 2*i : 24 + 2*i]) + for i in range(13, 16): + HomePlayers[i]['points'] = pn_points(pkg[11 + 2*i : 13 + 2*i]) + + elif sport_code == 0x39: # TENNIS + pass + + elif sport_code == 0x3A: # TABLE TENNIS + pass + + elif sport_code == 0x3C: # HANDBALL with individual penalties + pass + + elif sport_code == 0x62: # GUEST NAME + if pkg[2] == 0x20: + Game['guest_name'] = pn_name(pkg[6:48]) + with open(game_filename, 'w', encoding='utf-8') as f: + json.dump(Game, f, ensure_ascii=False, indent=4) + else: + GuestPlayers[int(pkg[2])]['number'] = pn_playernumber(pkg[51:53]) + GuestPlayers[int(pkg[2])]['name'] = pn_name(pkg[3:23]) + with open(guestplayers_filename, 'w', encoding='utf-8') as f: + json.dump(GuestPlayers, f, ensure_ascii=False, indent=4) + + elif sport_code == 0x77: # HOME NAME + if pkg[2] == 0x20: + Game['home_name'] = pn_name(pkg[6:48]) + with open(game_filename, 'w', encoding='utf-8') as f: + json.dump(Game, f, ensure_ascii=False, indent=4) + else: + HomePlayers[int(pkg[2])]['number'] = pn_playernumber(pkg[51:53]) + HomePlayers[int(pkg[2])]['name'] = pn_name(pkg[3:23]) + with open(homeplayers_filename, 'w', encoding='utf-8') as f: + json.dump(HomePlayers, f, ensure_ascii=False, indent=4) + + elif sport_code == 0x4D: # MESSAGE + GameHandFutsal.update({ + 'timer': pn_timer(pkg[4:8]), + 'horn': pn_horn(pkg[19]), + 'timer_status': pn_startstop(pkg[20]), + 'timer24': pn_timer24(pkg[48:50]), + 'horn24': pn_horn(pkg[50]), + 'timer24_status': pn_startstop(pkg[51]), + 'timer24_display': pn_display24(pkg[52]) + }) + + elif sport_code == 0x41 or sport_code == 0x043: # MESSAGE CONFIGURATION + GameHandFutsal.update({ + 'timer': pn_timer(pkg[4:8]), + 'horn': pn_horn(pkg[19]), + 'timer_status': pn_startstop(pkg[20]), + 'timer24': pn_timer24(pkg[48:50]), + 'horn24': pn_horn(pkg[50]), + 'timer24_status': pn_startstop(pkg[51]), + 'timer24_display': pn_display24(pkg[52]) + }) + + else: + print('Error: Unknown sport code {}'.format(sport_code)) + + +class REFClient(asyncore.dispatcher): + buff = [] + + def __init__(self, host, port): + asyncore.dispatcher.__init__(self) + self.create_socket() + self.connect( (host, port) ) + + def handle_connect(self): + pass + #print('Connect to referee system is established') + + def handle_close(self): + self.close() + + def handle_read(self): + buff = self.recv(8192) + if len(buff) == 54: + parce(buff) + +class JSONServer(BaseHTTPRequestHandler): + def do_GET(self): + if self.path == '/Game': + self.send_response(200) + self.send_header("Content-type", "application/json") + self.end_headers() + self.wfile.write(bytes(json.dumps([GameBasketball]), "utf-8")) + + elif self.path == '/GameBasketball': + self.send_response(200) + self.send_header("Content-type", "application/json") + self.end_headers() + self.wfile.write(bytes(json.dumps([GameBasketball]), "utf-8")) + + elif self.path == '/GameHandFutsal': + self.send_response(200) + self.send_header("Content-type", "application/json") + self.end_headers() + self.wfile.write(bytes(json.dumps([GameHandFutsal]), "utf-8")) + #GameHandFutsal + #self.wfile.write(bytes(json.dumps([GameHandFutsal]), "utf-8")) + + elif self.path == '/HomePlayers': + self.send_response(200) + self.send_header("Content-type", "application/json") + self.end_headers() + self.wfile.write(bytes(json.dumps(HomePlayers), "utf-8")) + + elif self.path == '/GuestPlayers': + self.send_response(200) + self.send_header("Content-type", "application/json") + self.end_headers() + self.wfile.write(bytes(json.dumps(GuestPlayers), "utf-8")) + + elif self.path == '/refresh': + self.send_response(200) + self.send_header("Content-type", "application/json") + self.end_headers() + self.wfile.write(bytes('[{"refresh":"ok"}]', "utf-8")) + + with io.open('C:/Users/aksma/YandexDisk/workspace/_hd1/_gfx/multisport_452/data.bin', 'rb') as f: + parce(f.read()) + + else: + self.send_response(200) + self.send_header("Content-type", "application/json") + self.end_headers() + self.wfile.write(bytes('[{"error":"bad path"}]', "utf-8")) + +if __name__ == "__main__": + + try: + with open(game_filename) as f: + Game = json.load(f) + with open(homeplayers_filename) as f: + HomePlayers = json.load(f) + with open(guestplayers_filename) as f: + GuestPlayers = json.load(f) + except: + pass + + webServer = HTTPServer((jsonserver_hostname, jsonserver_port), JSONServer) + print("Server started http://%s:%s" % (jsonserver_hostname, jsonserver_port)) + + client = REFClient(refserver_hostname, refserver_port) + + thread = threading.Thread(target=asyncore.loop, args=()) + thread.start() + print('Connect to referee system is established') + + try: + webServer.serve_forever() + except KeyboardInterrupt: + pass + + webServer.server_close() + print("Server stopped.") \ No newline at end of file diff --git a/divs/tcp_monitor.py b/divs/tcp_monitor.py new file mode 100644 index 0000000..9f02033 --- /dev/null +++ b/divs/tcp_monitor.py @@ -0,0 +1,34 @@ +import asyncore +from textwrap import wrap + +refserver_hostname = "79.172.5.168" +refserver_port = 4001 + +class REFClient(asyncore.dispatcher): + buff = '' + + def __init__(self, host, port): + asyncore.dispatcher.__init__(self) + self.create_socket() + self.connect( (host, port) ) + + def handle_connect(self): + pass + + def handle_close(self): + self.close() + + def handle_read(self): + hex = bytes.hex(self.recv(8192)) + hex = wrap(hex, 2) + print(' '.join(hex)) + +if __name__ == "__main__": + client = REFClient(refserver_hostname, refserver_port) + + try: + asyncore.loop() + except KeyboardInterrupt: + pass + + print("Server stopped.") \ No newline at end of file diff --git a/old/timer_MBA.py b/old/timer_MBA.py new file mode 100644 index 0000000..0e68524 --- /dev/null +++ b/old/timer_MBA.py @@ -0,0 +1,123 @@ +from socket import * +from datetime import datetime +import json +import time + +HOST = "10.0.0.57" # local +PORT = 50002 +ADDR = (HOST,PORT) + +PATH = "D:\\timer.json" + + +def connect(): + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect(ADDR) + data = "Hello, world" + data = str.encode(data) + tcp_socket.send(data) + data = bytes.decode(data) + data = tcp_socket.recv(1024) + # tcp_socket.close() + + return data + + +def save_log(name, data): + current_time = datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f") + message_with_time = f"[{current_time}] {data}" + with open(name, "a") as file: + file.write(message_with_time + "\n") + + +def formatted_data(data): + save_log("logs_mba.txt", data) + + # data_converted = list(data) + # data_formatted = [ + # str(hex_value // 16) + str(hex_value % 16) for hex_value in data_converted + # ] + # save_log("logs_mba_formatted.txt", data_formatted) + + +def parse(data_formatted): + # print(len(data_formatted)) + # print(data_formatted) + with open(PATH, "r", encoding="utf-8") as f: + new_data = json.load(f) + new_data = new_data[0] + + if len(data_formatted) > 30: + if data_formatted[17] == "010": + if data_formatted[-8] in ["01", "05"]: + timer_str = ( + f"{int(data_formatted[-7])}:{data_formatted[-6]}" + if int(data_formatted[-7]) != 0 + else f"{int(data_formatted[-6])}.{int(data_formatted[-5])}" + ) + new_data["timeGFX"] = timer_str + new_data["minutesGFX"] = int( + data_formatted[-7] + ) # [25] #data_formatted[17] = 010 - таймер data_formatted[-8] = 05 - овертайм, 06 - перерыв между основным временем и овертаймом, 01 - игровое время, 02 - перерыв между периодами + new_data["secondsGFX"] = data_formatted[-6] # [26] + else: + timer_str = f"{int(data_formatted[-7])}:{data_formatted[-6]}" + new_data["timeNotGame"] = timer_str + + if len(data_formatted) == 58: + new_data[ + "timeDel1" + ] = f"{int(data_formatted[26])}:{data_formatted[27]}" # data_formatted[17] = 24 - удаление + new_data["timeDel2"] = f"{int(data_formatted[41])}:{data_formatted[42]}" + + try: + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + print(new_data) + except Exception: + pass + + +def main(): + with socket(AF_INET, SOCK_STREAM) as s: + s.connect((HOST, PORT)) + s.sendall(b"Hello, world") + data = s.recv(1024) + while True: + print(data) + data_new = formatted_data(data) + time.sleep(.1) + # parse(data) + + + + + +def read_logs(): + import time + with open("test_logs_balashikha_new.txt", "r") as file: + for line in file: + parts = line.strip().split("] ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = parts[1] + parse(eval(data)) + if len(eval(data)) > 30 and eval(data)[-7] == "00": + time.sleep(.1) + else: + time.sleep(1) + + +if __name__ == "__main__": + new_data = { + "timeGFX": "0:00", + "minutesGFX": "0", + "secondsGFX": "0", + "foul1": "0", + "foul2": "0", + "quarter": "0", + } + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + main() + # read_logs() diff --git a/old/timer_MBA_2.py b/old/timer_MBA_2.py new file mode 100644 index 0000000..1213c18 --- /dev/null +++ b/old/timer_MBA_2.py @@ -0,0 +1,143 @@ +import sys +import json +from socket import * +from datetime import datetime +import time + + +host = "10.0.0.57" +port = 50002 +ADDR = (host, port) +PATH = "D:\\timer_basketball.json" + + +def save_log(name, data): + current_time = datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f") + message_with_time = f"[{current_time}] {data}" + with open(name, "a") as file: + file.write(message_with_time + "\n") + + +def parse(data): + data = data.split("/") + + with open(PATH, "r", encoding="utf-8") as f: + new_data = json.load(f) + new_data = new_data[0] + path_pic = "D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\VTB_Fouls for scoreboard smaller" + if len(data) > 10: + if data[4] == "NPR": + new_data["quarter"] = data[5] + if data[17] == "HCP": + new_data["points1"] = data[18] + if data[20] == "GCP": + new_data["points2"] = data[21] + if data[29] == "HCF": + new_data["foul1"] = data[30] + new_data["foul_pic1"] = path_pic + f"\Home тАУ {int(data[30])} Foul.png" + if data[32] == "GCF": + new_data["foul2"] = data[33] + new_data["foul_pic2"] = path_pic + f"\Away тАУ {int(data[33])} Foul.png" + else: + if data[1] == "TGI": + if data[2] != "0": + seconds = data[3] if len(data[3]) != 1 else f"0{data[3]}" + new_data["timeGFX"] = f"{data[2]}:{seconds}" + else: + millisec = data[4] + if millisec == "#": + millisec = "0" + new_data["timeGFX"] = f"{data[3]}.{millisec}" + elif data[1] == "NPR": + new_data["quarter"] = data[2] + elif data[1] == "HCP": + new_data["points1"] = data[2] + elif data[1] == "GCP": + new_data["points2"] = data[2] + elif data[1] == "HCF": + new_data["foul1"] = data[2] + new_data["foul_pic1"] = path_pic + f"\Home тАУ {int(data[2])} Foul.png" + elif data[1] == "GCF": + new_data["foul2"] = data[2] + new_data["foul_pic2"] = path_pic + f"\Away тАУ {int(data[2])} Foul.png" + elif data[1] == "TAI": + if data[2] not in ["0", "-1"]: + new_data["time_attackGFX"] = str(int(data[2])) + if int(data[2]) <= 5: + new_data["time_attac_pic"] = "" + else: + new_data["time_attac_pic"] = "empty" + + try: + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + print(new_data) + if ":" in new_data["timeGFX"]: + time.sleep(.5) + else: + time.sleep(.1) + + except Exception: + pass + + +def read_logs(): + with open("logs_mba_1.txt", "r") as file: + for line in file: + parts = line.strip().split("] ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = parts[1] + + parse(data) + + # if len(eval(data)) > 30 and eval(data)[-7] == "00": + # time.sleep(.1) + # else: + # time.sleep(1) + + +def main(): + new_data = { + "timeGFX": "0:00", + "time_attackGFX": "", + "quarter": "0", + "points1": "0", + "points2": "0", + "foul1": "0", + "foul2": "0", + "foul_pic1": "", + "foul_pic2": "", + "time_attac_pic": "", + } + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + + + + + + # tcp_socket = socket(AF_INET, SOCK_STREAM) + # tcp_socket.connect(ADDR) + + # try: + # while True: + # data = str.encode("hello") + # tcp_socket.send(data) + # data = bytes.decode(data) + # data = tcp_socket.recv(1024) + # data = data.decode() + # save_log("logs_mba_1.txt", data) + # parse(data) + # except KeyboardInterrupt: + # tcp_socket.close() + # sys.exit(1) + + +if __name__ == "__main__": + try: + main() + read_logs() + except KeyboardInterrupt: + sys.exit(1) + diff --git a/old/timer_Megasport_test.py b/old/timer_Megasport_test.py new file mode 100644 index 0000000..a1f3948 --- /dev/null +++ b/old/timer_Megasport_test.py @@ -0,0 +1,141 @@ +import sys +import json +from socket import * +from datetime import datetime +import logging +import os +import time +import binascii + +HOST = "192.168.127.254" +PORT = 1993 +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + + +def hexspace(string, length): + return " ".join(string[i : i + length] for i in range(0, len(string), length)) + + +def parse(line): + cdata = binascii.hexlify(line) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + + if len(edata.split()) == 33: + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + minutes = temp_new[6] + seconds = temp_new[7] + milliseconds = temp_new[8] + timer_str = ( + f"{minutes}:{seconds:02d}" + if minutes != 0 + else f"{seconds:02d}.{milliseconds}" + ) + active_temp = temp_new[ + 9 + ] # 133 - таймер идёт | 132 - таймер стоит | 128 - не игровое время стоит | 129 - не игровое время идёт + + if temp_new[-2] != 0: + time_attack = ( + temp_new[-4] if temp_new[-4] > 4 else f"{temp_new[-4]}.{temp_new[-3]}" + ) + else: + time_attack = "" # temp_new[-2] == 1 - таймер идёт | 2 - таймер стоит | 0 - таймер не отображён + + # print(f"{str(temp_new):<120}__{timer_str:<7}__{time_attack:<3}__") + else: + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + + with open("timer_NN.csv", "a+") as file: + file.write(str(temp_new)) + file.write("\n") + with open("timer_NN_2.csv", "a+") as file: + file.write(str(temp_data)) + file.write("\n") + with open("timer_NN_3.csv", "a+") as file: + file.write(str(ddata)) + file.write("\n") + + # time.sleep(0.1) + + +def read_logs(): + with open("timer_NN_2023-12-20_18-17-29.log", "r") as file: + # with open("timer_NN_test.log", "r") as file: + temp_line = "" + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = eval(parts[1]) + parse(data) + time.sllep(.1) + + # if len(eval(data)) > 30 and eval(data)[-7] == "00": + # time.sleep(.1) + # else: + # time.sleep(1) + + +def main(): + # current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + # if not os.path.isdir("LOGS"): + # os.mkdir("LOGS") + + # LogFileName = f"LOGS/timer_Chine_tcp_{current_time}.log" + # logging.basicConfig( + # level=logging.DEBUG, + # format="%(asctime)s %(levelname)s %(message)s", + # filename=LogFileName, + # filemode="w", + # ) + # new_data = { + # "timeGFX": "0:00", + # "time_attackGFX": "", + # "quarter": "0", + # "points1": "0", + # "points2": "0", + # "foul1": "0", + # "foul2": "0", + # "foul_pic1": "", + # "foul_pic2": "", + # "time_attac_pic": "", + # } + # with open(PATH, "w", encoding="utf-8") as file: + # json.dump([new_data], file, ensure_ascii=False, indent=4) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + # logging.debug(data) + cdata = binascii.hexlify(data) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + print(edata) + # temp_data = edata.split() + # temp_new = [int(t, 16) for t in temp_data] + # timer = f"{temp_new[3]}:{temp_new[2]}" + # seconds = temp_new[5] + # milliseconds = str(temp_new[4])[0] + # print(f"data: {edata}", temp_new, timer, f"{seconds}.{milliseconds}") + # print(temp_new, timer, f"{seconds}.{milliseconds}") + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + # read_logs() + except KeyboardInterrupt: + sys.exit(1) diff --git a/old/timer_megasport.py b/old/timer_megasport.py new file mode 100644 index 0000000..b11935f --- /dev/null +++ b/old/timer_megasport.py @@ -0,0 +1,82 @@ +# import serial.tools.list_ports #pip install pyserial + +import serial +from datetime import datetime +import json + +# Configure the COM port +port = "COM8" # Replace with the appropriate COM port name +baudrate = 9600 +# baudrate = 19200 +PATH = "D:\\timer_basketball.json" + + + +def save_log(name, data): + current_time = datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f") + message_with_time = f"[{current_time}] {data}" + with open(name, "a") as file: + file.write(message_with_time + "\n") + + +def read_logs(): + import time + + with open("logs_megasport_formatted.txt", "r") as file: + for line in file: + parts = line.strip().split("] ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = parts[1] + parse(eval(data)) + + input() + # if len(eval(data)) > 30 and eval(data)[-7] == "00": + # time.sleep(0.1) + # else: + # time.sleep(1) + + +def parse(data_formatted): + print(len(data_formatted)) + if len(data_formatted) > 8: + print(data_formatted) + with open(PATH, "r", encoding="utf-8") as f: + new_data = json.load(f) + new_data = new_data[0] + + + +def main(): + try: + # Open the COM port + ser = serial.Serial(port, baudrate=baudrate) + print("Serial connection established.") + + while True: + line = ser.readline() + line = list(line) + line = [str(hex_value // 16) + str(hex_value % 16) for hex_value in line] + save_log("logs_balashikha_formatted.txt", line) + print(line) + + except serial.SerialException as se: + print("Serial port error:", str(se)) + + except KeyboardInterrupt: + exit(1) + + finally: + if ser.is_open: + ser.close() + print("Serial connection closed.") + + +if __name__ == "__main__": + # new_data = { + # "timeGFX": "0:00", + # } + # with open(PATH, "w", encoding="utf-8") as file: + # json.dump([new_data], file, ensure_ascii=False, indent=4) + main() + # read_logs() diff --git a/old/timer_megasport2.py b/old/timer_megasport2.py new file mode 100644 index 0000000..6f64764 --- /dev/null +++ b/old/timer_megasport2.py @@ -0,0 +1,70 @@ +import serial +from serial import SerialException +import logging +import time +import binascii + +SerialPort = "COM1" +BaudRate = 19200 +PackageByTime = 0.1 +PackageByLenght = 256 +BufferMax = 2000 +LogFileName = "megasport_new_4.log" + +logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s %(levelname)s %(message)s', + filename=LogFileName, + filemode="w") + +ser = serial.Serial() +ser.port = SerialPort +ser.baudrate = BaudRate +ser.bytesize = serial.EIGHTBITS +ser.parity = serial.PARITY_NONE +ser.stopbits = serial.STOPBITS_ONE +ser.timeout = PackageByTime +ser.xonxoff = False +ser.rtscts = False +ser.dsrdtr = False +ser.write_timeout = 2 + +start = b"\xe0\xe0\xe8\xe8\xe4\xe4\xf8" +finish = b"\r" +while True: + try: + print("Initializing") + ser.close() + ser.open() + if ser.is_open: + try: + RequestCount = 0 + print("Port Opening") + RetryCount = 0 + remainder_hex = b"" + while True: + response = ser.read(PackageByLenght) + print(response) + + logging.debug(response) + if len(response) > 0: + + StarterTime = time.time() * 1000 + response_hex = response.replace(b" ", b"") + try: + int(response_hex,16) + except ValueError: + response_hex = binascii.hexlify(response) + response_hex = response_hex.upper() + + response_hex = remainder_hex + response_hex + print(response_hex) + + except Exception as e1: + logging.error("error communicating...: " + str(e1)) + else: + print("Port Opening Failed... trying again in 5 seconds") + time.sleep(5) + ser.close() + except SerialException: + print("No port connected... trying again in 5 seconds") + time.sleep(5) diff --git a/old/timer_megasport3.py b/old/timer_megasport3.py new file mode 100644 index 0000000..3548f57 --- /dev/null +++ b/old/timer_megasport3.py @@ -0,0 +1,58 @@ +import serial +from serial import SerialException +import logging +import time +import binascii + +SerialPort = "COM1" +BaudRate = 19200 +PackageByTime = 0.1 +PackageByLenght = 256 +BufferMax = 2000 +LogFileName = "megasport_new_4.log" + +logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s %(levelname)s %(message)s', + filename=LogFileName, + filemode="w") + +ser = serial.Serial() +ser.port = SerialPort +ser.baudrate = BaudRate +ser.bytesize = serial.EIGHTBITS +ser.parity = serial.PARITY_NONE +ser.stopbits = serial.STOPBITS_ONE +ser.timeout = PackageByTime +ser.xonxoff = False +ser.rtscts = False +ser.dsrdtr = False +ser.write_timeout = 2 + +# start = b"\xf8" +# finish = b"\r" +while True: + try: + print("Initializing") + ser.close() + ser.open() + if ser.is_open: + try: + RequestCount = 0 + print("Port Opening") + RetryCount = 0 + remainder_hex = b"" + while True: + response = ser.read(PackageByLenght) + print(response) + logging.debug(response) + + + except Exception as e1: + logging.error("error communicating...: " + str(e1)) + else: + print("Port Opening Failed... trying again in 5 seconds") + time.sleep(5) + ser.close() + except SerialException: + print("No port connected... trying again in 5 seconds") + time.sleep(5) diff --git a/old/timer_megasport5.py b/old/timer_megasport5.py new file mode 100644 index 0000000..4a12113 --- /dev/null +++ b/old/timer_megasport5.py @@ -0,0 +1,261 @@ +import serial +from serial import SerialException +import datetime +import binascii +import logging +import time +import json + +import re + +# Configuration Data (later to be put in Panel2Net.conf) +# SerialPort: Name of RPi serial port receiving the panel data +# SerialPort = "COM1" +SerialPort = "COM2" +# BaudRate: Serial port speed (Baud, Default will be adjusted later) +BaudRate = 19200 +# PackageByTime: Time Duration until a package is closed +# and sent off (seconds) +PackageByTime = 0.1 +# PackageByLength* Length (in bytes) of data input +# until a package is closed and sent off +PackageByLength = 128 +# PackageByLength = 256 попробовать нужно !!!!!!!!!!!!!!!!!!!! +# PackageByLength = 80 + +# MaxBuffer before flushing (in order to avoid buffer overflow) +BufferMax = 2000 + + +# LogFileName: Name of LogFile +current_time = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") +LogFileName = f"timer_megasport5_{current_time}.log" +# LogFileSize Maximum Size of LogFile (in Mbytes) +LogFileSize = 10 +# LogLevel Minimum Severity Level to be logged (see severity in Logs) +LogLevel = "E" + +logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", +) + +def hexspace(string, length): + return ' '.join(string[i:i+length] for i in range(0,len(string),length)) + +ser = serial.Serial() +ser.port = SerialPort +ser.baudrate = BaudRate +ser.bytesize = serial.EIGHTBITS +# number of bits per bytes +ser.parity = serial.PARITY_NONE +# set parity check: no parity +ser.stopbits = serial.STOPBITS_ONE +# number of stop bits +ser.timeout = PackageByTime +# non-block read +ser.xonxoff = False +# disable software flow control +ser.rtscts = False +# disable hardware (RTS/CTS) flow control +ser.dsrdtr = False +# disable hardware (DSR/DTR) flow control +ser.writeTimeout = 2 +# timeout for write + +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) +new_data = { + "timeGFX": "0.0", + "time_attackGFX": "", + "quarter": "0", + "points1": "0", + "points2": "0", + "foul1": "0", + "foul2": "0", + "foul_pic1": "", + "foul_pic2": "", + "time_attac_pic": "", +} +with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + + +while True: + try: + print("Initializing") + ser.close() + ser.open() + if ser.is_open: + try: + ser.reset_input_buffer() + # flush input buffer, discarding all its contents + ser.reset_output_buffer() + # flush output buffer, aborting current output + # and discard all that is in buffer + RequestCount = 0 + print("Port Opening") + # Initialise RetryCounter + RetryCount = 0 + # Initialise Variable to take remainder string + remainder_hex = b"" + + while True: + # Read from Serial Interface + response = ser.read(PackageByLength) + # print(response) + if len(response) > 0: + # In case there is something coming down the serial path + logging.debug(response) + + if response != b"": + data = response + # debug line + # f.write(data) + # f.write("\n") + + cdata = binascii.hexlify(data) + ddata = cdata.decode('utf-8') + ddata = ddata.upper() + print (ddata) + edata = hexspace(ddata, 2) + print (edata) + + + + # points1 = "" + # points2 = "" + # quarter = "" + # data_str = response.decode( + # "ascii", errors="ignore" + # ).replace("\r", "|") + # if len(data_str) == 53: + # pattern = r"^(3 0|7 |8 |69i553 |69i557 |69i558 |5:i553 )(.{4})" + # matches = re.findall(pattern, data_str) + # for match in matches: + # found_value = match[0] + # timer_str = match[1] + # if match[0] == "3 0": + # points1 = data_str[7:10].strip() + # points2 = data_str[10:13].strip() + # quarter = data_str[13:14].strip() + + # # print(f"Следующие 4 символа: {timer_str}, Найдено: {found_value}, {data_str}_____") + # else: + # pattern = r"(\|3 0|\|7 |\|8 |\|69i553 |\|69i557 |\|69i558 |\|5:i553 )(.{4})" + # matches = re.findall(pattern, data_str) + # # print(data_str) + # for match in matches: + # found_value = match[0] + # timer_str = match[1] + # if match[0] == "3 0": + # points1 = data_str[7:10].strip() + # points2 = data_str[10:13].strip() + # quarter = data_str[13:14].strip() + + # # print(f"Следующие 4 символа: {timer_str}, Найдено: {found_value}, {data_str}_____") + # pattern_attack = r"(.{5})\|" + # matches_attack = re.findall(pattern_attack, data_str) + # path_pic = r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators" + # try: + # if matches_attack[0][2:] == "030": + # time_attackGFX = "" + # time_attac_pic = path_pic + "\\24Sec_empty.png" + # else: + # hex_dict = { + # "I": 9, + # "H": 8, + # "G": 7, + # "F": 6, + # "E": 5, + # "D": 4, + # "C": 3, + # "B": 2, + # "A": 1, + # } + # time_attackGFX = matches_attack[0][:2] + # if time_attackGFX[-1] in [ + # "A", + # "B", + # "C", + # "D", + # "E", + # "F", + # "G", + # "H", + # "I", + # ]: + # first_character = time_attackGFX[0] + # second_character = time_attackGFX[1] + # time_attackGFX = str( + # int(first_character, 16) + # + hex_dict.get(second_character, 0) / 10.0 + # ) + # time_attac_pic = path_pic + "\\24Sec_Red.png" + # else: + # time_attac_pic = path_pic + "\\24Sec_Orange.png" + # except IndexError: + # pass + + # if timer_str[0] == " ": + # if timer_str == " 000": + # timer = "0.0" + # else: + # minites = timer_str[:2] + # seconds = timer_str[2:] + # timer = f"{int(minites)}:{seconds}".strip() + # elif timer_str[-1] == " ": + # seconds = timer_str[:2] + # milliseconds = timer_str[2:] + # timer = f"{int(seconds)}.{milliseconds}".strip() + # else: + # minites = timer_str[:2] + # seconds = timer_str[2:] + # timer = f"{int(minites)}:{seconds}".strip() + + # print( + # f"Следующие 4 символа: {timer_str}, {timer}, {time_attackGFX}, Найдено: {found_value}, {data_str}_____" + # ) + + # with open(PATH, "r", encoding="utf-8") as f: + # new_data = json.load(f) + # new_data = new_data[0] + # new_data["timeGFX"] = timer + # new_data["time_attackGFX"] = time_attackGFX + # new_data["time_attac_pic"] = time_attac_pic + # if points1: + # new_data["points1"] = points1 + # new_data["points2"] = points2 + # new_data["quarter"] = quarter + # try: + # with open(PATH, "w", encoding="utf-8") as file: + # json.dump( + # [new_data], file, ensure_ascii=False, indent=4 + # ) + # except Exception: + # pass + + else: + # In case nothing is coming down the serial interface + print( + "\rWaiting for serial input...", + end=" ", + flush=True, + ) + + # in case that the Serial Read or HTTP request fails + except Exception as e1: + print("error communicating...: " + str(e1)) + logging.error("error communicating...: " + str(e1)) + + else: + print("Port Opening Failed... trying again in 5 seconds") + time.sleep(0.1) + ser.close() + + except SerialException: + print("No port connected... trying again in 5 seconds") + time.sleep(0.1) diff --git a/old/timer_megasport_rider.py b/old/timer_megasport_rider.py new file mode 100644 index 0000000..2b61067 --- /dev/null +++ b/old/timer_megasport_rider.py @@ -0,0 +1,25 @@ +start = "\xf8" +finish = "\r" + +with open('megasport_new_5.txt', 'r') as file: + new_lines = [] + current_line = "" + capturing = False + + for line in file: + if start in line: + capturing = True + current_line = line[line.index(start):] + elif capturing: + if finish in line: + finish_idx = line.index(finish) + current_line += line[:finish_idx + len(finish)] + new_lines.append(current_line) + current_line = "" + capturing = False + else: + current_line += line + +with open('new_log.txt', 'w') as new_file: + for line in new_lines: + new_file.write(line + '\n') diff --git a/timer COM copy.py b/timer COM copy.py new file mode 100644 index 0000000..930386f --- /dev/null +++ b/timer COM copy.py @@ -0,0 +1,363 @@ +# vmix_serial_bridge.py +# pip install pyserial requests + +import time +import argparse +import urllib.parse +import requests +import serial +from serial.serialutil import SerialException +from serial.tools import list_ports +import re +from dataclasses import dataclass +from threading import Thread, Event +from queue import Queue, Empty + +VMIX_HOST = "http://127.0.0.1:8088" + +VMIX_TARGETS = { + "main_time": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "TIMER.Text", "SelectedIndex": None}, + "shot_clock": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "24sec.Text", "SelectedIndex": None}, + "quarter": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "QUARTER.Text", "SelectedIndex": None}, + "score_1": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "SCORE1.Text", "SelectedIndex": None}, + "score_2": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "SCORE2.Text", "SelectedIndex": None}, + "fouls_1": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "FOULS1.Text", "SelectedIndex": None}, + "fouls_2": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "FOULS2.Text", "SelectedIndex": None}, +} + +# ---------------- HTTP client ---------------- +class VmixClient: + def __init__(self, host: str, timeout: float = 0.01, retries: int = 3, backoff: float = 0.3): + self.host = host.rstrip("/") + self.timeout = timeout + self.retries = retries + self.backoff = backoff + self.session = requests.Session() + self.session.headers.update({"Connection": "keep-alive"}) + + def call(self, function: str, input_id: str, value: str, selected_name=None, selected_index=None) -> bool: + params = {"Function": function, "Input": input_id, "Value": value} + if selected_name: + params["SelectedName"] = selected_name + if selected_index is not None: + params["SelectedIndex"] = selected_index + url = f"{self.host}/api?{urllib.parse.urlencode(params, doseq=True, safe='')}" + for attempt in range(1, self.retries + 2): + try: + r = self.session.get(url, timeout=self.timeout) + print(r.status_code()) + r.raise_for_status() + return True + except requests.RequestException as e: + if attempt > self.retries: + print(f"[vMix] ERROR: {e} -> {url}") + return False + delay = self.backoff * attempt + print(f"[vMix] WARN attempt {attempt}: {e}. Retry in {delay:.2f}s") + time.sleep(delay) + +@dataclass +class VmixMessage: + field: str + value: str + +class VmixSender: + def __init__(self, client: VmixClient, dedupe: bool = False, max_queue: int = 2000): + self.client = client + self.queue: Queue[VmixMessage] = Queue(maxsize=max_queue) + self.stop_event = Event() + self.thread = Thread(target=self._run, name="vmix-sender", daemon=True) + self.dedupe = dedupe + self._last_sent: dict[str, str | None] = {} + + def start(self): self.thread.start() + def stop(self): self.stop_event.set(); self.thread.join(timeout=2) + + # VmixSender + def send(self, field: str, value: str | None): + if value is None: + return + if field not in VMIX_TARGETS: + return + if self.dedupe and self._last_sent.get(field) == value: + return + if self.dedupe: + self._last_sent[field] = value + try: + self.queue.put_nowait(VmixMessage(field, str(value))) + except Exception: + try: + _ = self.queue.get_nowait(); self.queue.task_done() + except Empty: + pass + self.queue.put_nowait(VmixMessage(field, str(value))) + + + def _run(self): + while not self.stop_event.is_set(): + try: + msg = self.queue.get(timeout=0.2) + except Empty: + continue + t = VMIX_TARGETS[msg.field] + ok = self.client.call(t["Function"], t["Input"], msg.value, t.get("SelectedName"), t.get("SelectedIndex")) + if ok: print(f"[vMix] {msg.field} <- {msg.value}") + self.queue.task_done() + +# ---------------- Parser ---------------- +def parse_time_5ch(chunk: str) -> str | None: + if len(chunk) != 5: return None + try: + if chunk[0:2] == "0 ": + return f"{int(chunk[1:3])}:{int(chunk[3:5]):02d}" + # elif len(chunk) == 5: + # return f"{int(chunk[1:3])}:{int(chunk[3:5]):02d}" + else: + return f"{int(chunk[1:3])}.{chunk[3]}" + except Exception: + return None + +def format_shot_clock_from_tail_number(n: int) -> str | None: + if n < 0: return "" + tail = n % 100 + if tail != 31: return "" # не обновлять + sec_tenths = n // 100 + return str(sec_tenths // 10) if sec_tenths >= 50 else f"{sec_tenths / 10:.1f}" + +@dataclass +class ParsedPacket: + main_time: str | None = None + score1: str | None = None + score2: str | None = None + quarter: str | None = None + shot_clock: str | None = None + +def parse_line(line: str) -> ParsedPacket | None: + clean = line.strip().replace("�", "") + print(clean) + # if not clean or len(clean) < 24: return None + try: + if clean[0] != "3": return None + except Exception: + return None + main_time_raw = clean[2:7] + main_time = parse_time_5ch(main_time_raw) + # print(main_time) + + score1 = clean[7:10].strip() + score2 = clean[10:13].strip() + + quarter = None + m = re.search(r"\s([1-5])\s\s\d{6}\s", clean) + if m: quarter = m.group(1) + + shot_clock = "" + tail = clean[-5:] + if tail.isdigit(): + shot_clock = format_shot_clock_from_tail_number(int(tail)) + return ParsedPacket( + main_time=main_time, + score1=score1 or None, + score2=score2 or None, + quarter=quarter, + shot_clock=shot_clock, + ) + +# ---------------- Serial reader ---------------- +EOLS = {"CR": b"\r", "LF": b"\n", "CRLF": b"\r\n"} + +def sniff_eol(sample: bytes) -> bytes: + # простейшая эвристика + if b"\r\n" in sample: return EOLS["CRLF"] + if b"\r" in sample and b"\n" not in sample: return EOLS["CR"] + if b"\n" in sample: return EOLS["LF"] + return EOLS["CR"] # дефолт + +class SerialReader: + def __init__(self, port: str, baud: int, newline: str, strip_ws: bool, sender: VmixSender, + send_quarter: bool, autoeol: bool, bytesize: int, parity: str, stopbits: float, + rtscts: bool, xonxoff: bool, dsrdtr: bool): + self.port = port + self.baud = baud + self.eol = EOLS.get(newline.upper(), b"\r") + self.strip_ws = strip_ws + self.sender = sender + self.send_quarter = send_quarter + self.autoeol = autoeol + self.bytesize = bytesize + self.parity = getattr(serial, f"PARITY_{parity.upper()}", serial.PARITY_NONE) + self.stopbits = {1: serial.STOPBITS_ONE, 1.5: serial.STOPBITS_ONE_POINT_FIVE, 2: serial.STOPBITS_TWO}[stopbits] + self.rtscts = rtscts + self.xonxoff = xonxoff + self.dsrdtr = dsrdtr + + def run(self): + while True: + try: + with serial.Serial( + self.port, + baudrate=self.baud, + timeout=0.01, + bytesize=self.bytesize, + parity=self.parity, + stopbits=self.stopbits, + rtscts=self.rtscts, + xonxoff=self.xonxoff, + dsrdtr=self.dsrdtr, + ) as ser: + print(f"[serial] OPEN {ser.port} @ {self.baud} ({self.bytesize}{self._parity_name()}{self._stopbits_name()})") + # сбросим линии и буферы + try: + ser.setDTR(True); ser.setRTS(True) + except Exception: pass + ser.reset_input_buffer(); ser.reset_output_buffer() + + buffer = bytearray() + last_feed = time.time() + # авто-детект EOL по первому куску + if self.autoeol: + chunk = ser.read(256) + if chunk: + self.eol = sniff_eol(chunk) + print(f"[serial] auto EOL = {self._eol_name(self.eol)}") + buffer.extend(chunk) + + while True: + chunk = ser.read(1024) + if chunk: + buffer.extend(chunk) + last_feed = time.time() + + # разбор по EOL + progressed = False + while True: + idx = buffer.find(self.eol) + if idx == -1: break + line = buffer[:idx] + del buffer[: idx + len(self.eol)] + text = self._decode(line, self.strip_ws) + if text: + self._process(text) + progressed = True + + # фолбэк: если долго не было EOL, попробуем отдать «как есть» + if not progressed and buffer and (time.time() - last_feed) > 0.5: + text = self._decode(buffer, self.strip_ws) + buffer.clear() + if text: + self._process(text) + + except SerialException as e: + print(f"[serial] ERROR open/read {self.port}: {e}. Retry in 3s...") + time.sleep(3) + except KeyboardInterrupt: + print("\n[serial] Stopped by user.") + return + except Exception as e: + print(f"[serial] UNEXPECTED: {e}. Retry in 3s...") + time.sleep(3) + + def _decode(self, raw: bytes, strip_ws: bool) -> str | None: + try: + text = raw.decode("utf-8", errors="replace") + except Exception: + text = raw.decode("latin-1", errors="replace") + if strip_ws: text = text.strip() + return text or None + + def _process(self, text: str): + pkt = parse_line(text) + if not pkt: + print(f"[serial] RAW: {text!r}") + return + if pkt.main_time is not None: self.sender.send("main_time", pkt.main_time) + if pkt.score1 is not None: self.sender.send("score_1", pkt.score1) + if pkt.score2 is not None: self.sender.send("score_2", pkt.score2) + if self.send_quarter and pkt.quarter is not None: + self.sender.send("quarter", pkt.quarter) + if pkt.shot_clock is not None: + self.sender.send("shot_clock", pkt.shot_clock) + + def _parity_name(self): return {"N":"N","E":"E","O":"O","M":"M","S":"S"}[self.parity] + def _stopbits_name(self): return {serial.STOPBITS_ONE:"1", serial.STOPBITS_ONE_POINT_FIVE:"1.5", serial.STOPBITS_TWO:"2"}[self.stopbits] + def _eol_name(self, e: bytes): return {b"\r":"CR", b"\n":"LF", b"\r\n":"CRLF"}.get(e, f"{e!r}") + +# ---------------- Probe (sniffer) ---------------- +def probe_port(port: str, baud: int, seconds: int, **kwargs): + print("[probe] Available ports:") + for p in list_ports.comports(): + print(f" - {p.device}: {p.description}") + try: + with serial.Serial(port, baudrate=baud, timeout=0.01) as ser: + print(f"[probe] OPEN {ser.port} @ {baud}. Sniffing {seconds}s...") + ser.reset_input_buffer() + t0 = time.time() + total = 0 + while time.time() - t0 < seconds: + b = ser.read(512) + if not b: continue + total += len(b) + print(f"[{len(b):03d} bytes] HEX: {b.hex(' ')}") + try: + txt = b.decode("utf-8") + except Exception: + txt = b.decode("latin-1", errors="replace") + print(f" TXT: {txt!r}") + print(f"[probe] Done. Total bytes: {total}") + except Exception as e: + print(f"[probe] ERROR: {e}") + +# ---------------- CLI ---------------- +def main(): + ap = argparse.ArgumentParser(description="COM -> vMix bridge with diagnostics") + ap.add_argument("--port", required=True, help="e.g. COM2 or /dev/ttyUSB0") + ap.add_argument("--baud", type=int, default=19200) + ap.add_argument("--newline", choices=["LF", "CRLF", "CR"], default="CR") + ap.add_argument("--autoeol", action="store_true", help="Auto-detect EOL from stream") + ap.add_argument("--no-strip", action="store_true") + ap.add_argument("--vmix-host", default=VMIX_HOST) + ap.add_argument("--timeout", type=float, default=0.01) + ap.add_argument("--retries", type=int, default=3) + ap.add_argument("--backoff", type=float, default=0.3) + ap.add_argument("--dedupe", action="store_true") + ap.add_argument("--send-quarter", action="store_true") + # serial low-level + ap.add_argument("--bytesize", type=int, choices=[5,6,7,8], default=8) + ap.add_argument("--parity", choices=["N","E","O","M","S"], default="N") + ap.add_argument("--stopbits", type=float, choices=[1,1.5,2], default=1) + ap.add_argument("--rtscts", action="store_true") + ap.add_argument("--xonxoff", action="store_true") + ap.add_argument("--dsrdtr", action="store_true") + # tools + ap.add_argument("--probe", type=int, metavar="SECONDS", help="Sniff raw bytes/text for N seconds and exit") + args = ap.parse_args() + + if args.probe: + probe_port(args.port, args.baud, args.probe) + return + + client = VmixClient(host=args.vmix_host, timeout=args.timeout, retries=args.retries, backoff=args.backoff) + sender = VmixSender(client=client, dedupe=args.dedupe); sender.start() + + reader = SerialReader( + port=args.port, + baud=args.baud, + newline=args.newline, + strip_ws=not args.no_strip, + sender=sender, + send_quarter=args.send_quarter, + autoeol=args.autoeol, + bytesize=args.bytesize, + parity=args.parity, + stopbits=args.stopbits, + rtscts=args.rtscts, + xonxoff=args.xonxoff, + dsrdtr=args.dsrdtr, + ) + try: + reader.run() + finally: + sender.stop() + +if __name__ == "__main__": + main() diff --git a/timer COM.py b/timer COM.py new file mode 100644 index 0000000..24d3648 --- /dev/null +++ b/timer COM.py @@ -0,0 +1,345 @@ +# serial_to_vmix.py +# pip install pyserial requests + +import time +import argparse +import socket +import urllib.parse +import requests +import serial +from serial.serialutil import SerialException + +# --------------------------- +# 1) ВАША функция отправки в vMix +# Замените содержимое по своему желанию. +# --------------------------- +# --- ВСТАВЬТЕ ВАШ serial_to_vmix.py вместо заглушки parse() --- + +import re +from dataclasses import dataclass, asdict + +session = requests.Session() +session.headers.update({"Connection": "keep-alive"}) + +VMIX_HOST = "http://127.0.0.1:8088" # адрес vMix Web Controller + +# куда писать поля в vMix — укажите свои Inputs/поля титров +# 1) В блоке VMIX_TARGETS добавьте цель для секундника: +VMIX_TARGETS = { + "main_time": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "TIMER.Text", "SelectedIndex": None}, + "shot_clock": {"Function": "SetText", "Input": "SCOREBUG","SelectedName": "24sec.Text", "SelectedIndex": None}, # ⬅️ ДОБАВЛЕНО + "quarter": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": None, "SelectedIndex": None}, + "score_1": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "SCORE1.Text", "SelectedIndex": None}, + "score_2": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "SCORE2.Text", "SelectedIndex": None}, + "fouls_1": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": None, "SelectedIndex": None}, + "fouls_2": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": None, "SelectedIndex": None}, +} + +def vmix_call(function: str, input_id: str, value: str, selected_name=None, selected_index=None, timeout=1.5): + params = {"Function": function, "Input": input_id, "Value": value} + if selected_name: + params["SelectedName"] = selected_name + if selected_index: + params["SelectedIndex"] = selected_index + url = f"{VMIX_HOST}/api?{urllib.parse.urlencode(params, doseq=True, safe='')}" + try: + r = session.get(url, timeout=timeout) + r.raise_for_status() + except requests.RequestException as e: + print(f"[vMix] HTTP ошибка: {e} -> {url}") + +# 2) В State замените shot_clock (int) на текстовый shot_clock (str), чтобы иногда писать десятые: +@dataclass +class State: + main_time: str | None = None # "M:SS" + shot_clock: str | None = None # ⬅️ теперь строка: "21" или "4.9" + quarter: int | None = None + score_1: int | None = None + score_2: int | None = None + fouls_1: int | None = None + fouls_2: int | None = None + timeouts_1: int | None = None + timeouts_2: int | None = None + + +class SmartBasketParser: + # строка «наша» если начинается с мусора и цифры 3, и содержит блок 0000 + full_line_guard = re.compile(r'^\D*3\b') + re_numbers = re.compile(r"\d+") + + def __init__(self): + self.state = State() + + @staticmethod + def _mmss_to_str(n: int) -> str: + """ + Универсальный форматтер: + - < 100 -> 'ss:0' + - 3 цифры, s<=59 -> 'M:SS' (MMSS) + - 3 цифры, s>59 -> 'ss:ms' (SSd, где ms = десятые) + - 4 цифры -> 'M:SS' (MMSS) + """ + if n < 0: + return "0:00" + + # только секунды + if n < 100: + ss = max(0, min(n, 59)) + return f"{ss}:0" + + # 3 цифры: либо M:SS, либо SS.d + if 100 <= n <= 999: + m = n // 100 + s = n % 100 + if s <= 59: + return f"{m}:{s:02d}" # 102 -> 1:02 + else: + ss = n // 10 # 199 -> 19 + d = n % 10 # 199 -> 9 + return f"{ss}.{d}" # 199 -> 19:9 + + # 4 цифры: MMSS + if 1000 <= n <= 5959: + m, s = divmod(n, 100) + if s >= 60: + m += s // 60 + s = s % 60 + return f"{m}:{s:02d}" + + # всё прочее не считаем временем + return "0:00" + + def _pick_main_time(self, nums: list[int]) -> str | None: + """ + В 'полной' строке основное время идёт сразу после ведущей '3'. + Если следом '0' — берём через один. + Примеры: + [3, 0, 58, 35, 35, 2200, 1, ...] -> 58:0 + [3, 199, 2, 13200, 1, ...] -> 19:9 + [3, 102, 35, 35, 0000, 1, ...] -> 1:02 + """ + if not nums: + return None + # nums[0] — это 3 + idx = 1 + if len(nums) > 1 and nums[1] == 0: + idx = 2 + if idx < len(nums): + t = nums[idx] + # считаем временем только разумные токены: секунды/3-цифр. спец./MMSS + if (0 <= t <= 59) or (100 <= t <= 999) or (1000 <= t <= 5959): + return self._mmss_to_str(t) + + # fallback (на всякий): ищем первый разумный токен до первого 4-значного блока + idx_flags = next((i for i, n in enumerate(nums) if len(str(n)) == 4), None) + search_upto = idx_flags if idx_flags is not None else len(nums) + for n in nums[:search_upto]: + if (0 <= n <= 59) or (100 <= n <= 999) or (1000 <= n <= 5959): + return self._mmss_to_str(n) + + return None + + @staticmethod + def _format_main_time_compact(n: int) -> str: + """ + Компактный формат 'MMSSd' (например, 13200 -> 13:20.0). + m = n // 1000 + s = (n // 10) % 100 + d = n % 10 (десятые) + Вывод: если m>0 -> 'M:SS', если m==0 -> 'SS:d' (как вы просили '< 1 мин — ss:ms'). + """ + if n < 0: + return "0:00" + m = n // 1000 + s = (n // 10) % 100 + d = n % 10 + if s >= 60: # подстраховка + m += s // 60 + s = s % 60 + if m > 0: + return f"{m}:{s:02d}" + else: + return f"{s}:{d}" + + def _format_shot_clock_from_tail_number(self, n: int) -> str | None: + """ + n — последнее число в строке (например, 21031). + Правило валидности: если последние две цифры == 31 — обновляем таймер, + если == 30 (или не 31) — не обновляем (возвращаем None). + Расчёт: отбрасываем две последние цифры -> n // 100 (секунды * 10). + >= 50 -> целые секунды ('21', '20', ...), иначе -> десятые ('4.9', ...). + """ + if n < 0: + return None + + tail = n % 100 + if tail != 31: + # 30 — специально игнорируем; всё, что не 31 — тоже игнорим + return None + + sec_tenths = n // 100 # «секунды × 10» + if sec_tenths >= 50: + return str(sec_tenths // 10) # «21», «20», ... + else: + return f"{sec_tenths / 10:.1f}" # «4.9», «4.8», ..., «0.0» + + + def _pick_scores_flags_and_quarter(self, nums: list[int]): + """ + Ищем последовательность: ... s1 s2 F1F2T1T2 Q ... + СЧЁТ ОБНОВЛЯЕМ ТОЛЬКО если нашли 4-значный блок флагов (1000..9999). + Если флагов нет — возвращаем None для счёта/флагов/четверти, + чтобы не перезатирать корректные прошлые значения. + """ + score1 = score2 = fouls1 = fouls2 = to1 = to2 = quarter = None + + # найдём первый 4-значный блок (флаги) + idx_flags = next((i for i, n in enumerate(nums) if 1000 <= n <= 9999), None) + if idx_flags is None: + # нет флагов -> ничего не обновляем + return score1, score2, fouls1, fouls2, to1, to2, quarter + + # перед флагами должны стоять два счёта + if idx_flags >= 2: + s1, s2 = nums[idx_flags - 2], nums[idx_flags - 1] + if 0 <= s1 <= 300 and 0 <= s2 <= 300: + score1, score2 = s1, s2 + + # разбираем флаги F1F2T1T2 + f = f"{nums[idx_flags]:04d}" + fouls1, fouls2, to1, to2 = map(int, f) + + # четверть — число сразу после флагов (1..10) + if idx_flags + 1 < len(nums): + q = nums[idx_flags + 1] + if 1 <= q <= 10: + quarter = q + + return score1, score2, fouls1, fouls2, to1, to2, quarter + + # 4) В parse_line() после nums = [...] добавьте вычисление секундника: + def parse_line(self, line: str) -> State | None: + if not (self.full_line_guard.search(line) and "0000" in line): + return None + + parts = self.re_numbers.findall(line) + if not parts: + return None + nums = [int(p) for p in parts] + + main_time_str = self._pick_main_time(nums) + s1, s2, f1, f2, to1, to2, q = self._pick_scores_flags_and_quarter(nums) + + # ⬇️ новый блок: секундник из последнего числа + # shot_clock_text = "" + # ⬇️ новый безопасный блок секундника + shot_clock_text = self.state.shot_clock # по умолчанию — предыдущее значение + if nums: # nums уже есть выше: nums = [int(p) for p in parts] + sc_new = self._format_shot_clock_from_tail_number(nums[-1]) + if sc_new is not None: + shot_clock_text = sc_new + + out = State( + main_time=main_time_str or self.state.main_time, + shot_clock=shot_clock_text, + score_1 = s1 if s1 is not None else self.state.score_1, + score_2 = s2 if s2 is not None else self.state.score_2, + fouls_1 = f1 if f1 is not None else self.state.fouls_1, + fouls_2 = f2 if f2 is not None else self.state.fouls_2, + timeouts_1 = to1 if to1 is not None else self.state.timeouts_1, + timeouts_2 = to2 if to2 is not None else self.state.timeouts_2, + quarter = q if q is not None else self.state.quarter, +) + return out + + def update_and_push(self, new_state: State): + old = self.state + for k, v in asdict(new_state).items(): + if getattr(old, k) != v and v is not None: + self._push_to_vmix(k, v) + self.state = new_state + + # 5) В _push_to_vmix оставьте как есть — он уже приводит value к строке. + # Если хотите реально отправлять в vMix — раскомментируйте vmix_call: + + def _push_to_vmix(self, key: str, value): + t = VMIX_TARGETS.get(key) + if not t: + return + # 👉 РАСКОММЕНТИРУЙТЕ для отправки в vMix + vmix_call( + function=t["Function"], + input_id=t["Input"], + value=str(value), + selected_name=t.get("SelectedName"), + selected_index=t.get("SelectedIndex"), + ) + # print(f"[push] {key} = {value}") + +_parser = SmartBasketParser() + +def parse(data: str): + print(data) + st = _parser.parse_line(data) + if st: + _parser.update_and_push(st) + else: + # полезно видеть, что игнорируем — закомментируйте, если мешает + print("[parse] пропуск строки (не формат �����3 + 0000)") + +# --------------------------- +# 2) Чтение из COM-порта и вызов parse +# --------------------------- +def read_loop(port: str, baud: int, newline: str, strip_whitespace: bool): + # мапинг для окончания строк в pyserial + eol = {"CRLF": b"\r\n", "LF": b"\n", "CR": b"\r"}.get(newline.upper(), b"\n") + + while True: + try: + with serial.Serial(port, baudrate=baud) as ser: + print(f"[serial] открыт {ser.port} @ {baud} бод. Ожидаю данные...") + buffer = bytearray() + while True: + chunk = ser.read(1024) + if not chunk: + continue + buffer.extend(chunk) + # разбираем по разделителю строк + while True: + idx = buffer.find(eol) + if idx == -1: + break + line = buffer[:idx] + del buffer[:idx + len(eol)] + try: + text = line.decode("utf-8", errors="replace") + except Exception: + text = line.decode("latin-1", errors="replace") + if strip_whitespace: + text = text.strip() + if text != "": + parse(text) + except SerialException as e: + print(f"[serial] не удалось открыть/читать {port}: {e}. Повтор через 3 сек...") + time.sleep(3) + except KeyboardInterrupt: + print("\n[serial] остановлено пользователем.") + break + except Exception as e: + print(f"[serial] непредвиденная ошибка: {e}. Повтор через 3 сек...") + time.sleep(3) + +def main(): + ap = argparse.ArgumentParser(description="Чтение COM и отправка в vMix через parse()") + ap.add_argument("--port", required=True, help="COM-порт, напр. COM3 (Windows) или /dev/ttyUSB0 (Linux)") + ap.add_argument("--baud", type=int, default=19200, help="Скорость, по умолчанию 19200") + ap.add_argument("--newline", choices=["LF", "CRLF", "CR"], default="CR", + help="Разделитель строк, по умолчанию LF") + ap.add_argument("--no-strip", action="store_true", + help="Не обрезать пробелы по краям (по умолчанию обрезаем)") + args = ap.parse_args() + + read_loop(args.port, args.baud, args.newline, strip_whitespace=not args.no_strip) + +if __name__ == "__main__": + main() diff --git a/timer COM3.py b/timer COM3.py new file mode 100644 index 0000000..064a117 --- /dev/null +++ b/timer COM3.py @@ -0,0 +1,486 @@ +# vmix_serial_bridge_optimized.py +# pip install pyserial requests + +""" +Оптимизированная версия COM -> vMix моста для максимально быстрой доставки +данных в vMix. Ключевые изменения: +- Немедленная обработка входящих байт: неблокирующее чтение с малой задержкой + (timeout) и мгновенная отправка строк при появлении EOL или коротком «простоя». +- Параметризуемые интервалы: --read-timeout, --idle-flush для тонкой настройки + задержки между получением и отправкой. +- Убраны лишние print'ы, добавлен флаг --verbose для отладки без штрафа к скорости. +- Дедупликация значений к vMix включаемая флагом (по умолчанию включена). +- Предкомпиляция регулярных выражений и мелкие микроптимизации парсера. +- Очередь отправки без блокировок и аккуратное «сбросить-старое-сообщение» поведение + на переполнении. + +Совместима с прежней CLI, но добавлены новые опции: + --read-timeout (сек, по умолчанию 0.03) + --idle-flush (сек, по умолчанию 0.06) + --max-chunk (байт, по умолчанию 512) + --verbose (подробные логи) + +Пример запуска: + python vmix_serial_bridge_optimized.py --port COM2 --baud 19200 --autoeol \ + --send-quarter --dedupe --read-timeout 0.02 --idle-flush 0.05 +""" + +import time +import argparse +import urllib.parse +import requests +import serial +from serial.serialutil import SerialException +from serial.tools import list_ports +import re +from dataclasses import dataclass +from threading import Thread, Event +from queue import Queue, Empty +from typing import Optional, Dict + +VMIX_HOST = "http://127.0.0.1:8088" + +VMIX_TARGETS = { + "main_time": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "TIMER.Text", "SelectedIndex": None}, + "shot_clock": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "24sec.Text", "SelectedIndex": None}, + "quarter": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "QUARTER.Text", "SelectedIndex": None}, + "score_1": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "SCORE1.Text", "SelectedIndex": None}, + "score_2": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "SCORE2.Text", "SelectedIndex": None}, + "fouls_1": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "FOULS1.Text", "SelectedIndex": None}, + "fouls_2": {"Function": "SetText", "Input": "SCOREBUG", "SelectedName": "FOULS2.Text", "SelectedIndex": None}, +} + +# ---------------- HTTP client ---------------- +class VmixClient: + def __init__(self, host: str, timeout: float = 0.01, retries: int = 2, backoff: float = 0.2): + self.host = host.rstrip("/") + self.timeout = timeout + self.retries = retries + self.backoff = backoff + self.session = requests.Session() + self.session.headers.update({"Connection": "keep-alive"}) + + def call(self, function: str, input_id: str, value: str, selected_name=None, selected_index=None) -> bool: + params = {"Function": function, "Input": input_id, "Value": value} + if selected_name: + params["SelectedName"] = selected_name + if selected_index is not None: + params["SelectedIndex"] = selected_index + url = f"{self.host}/api?{urllib.parse.urlencode(params, doseq=True, safe='')}" + for attempt in range(1, self.retries + 2): + try: + r = self.session.get(url, timeout=self.timeout) + r.raise_for_status() + return True + except requests.RequestException as e: + if attempt > self.retries: + return False + time.sleep(self.backoff * attempt) + return False + +@dataclass +class VmixMessage: + field: str + value: str + +class VmixSender: + def __init__(self, client: VmixClient, dedupe: bool = True, max_queue: int = 4096, verbose: bool = False): + self.client = client + self.queue: Queue[VmixMessage] = Queue(maxsize=max_queue) + self.stop_event = Event() + self.thread = Thread(target=self._run, name="vmix-sender", daemon=True) + self.dedupe = dedupe + self._last_sent: Dict[str, Optional[str]] = {} + self.verbose = verbose + + def start(self): + self.thread.start() + + def stop(self): + self.stop_event.set() + self.thread.join(timeout=2) + + def send(self, field: str, value: Optional[str]): + if value is None: + return + if field not in VMIX_TARGETS: + return + if self.dedupe and self._last_sent.get(field) == value: + return + if self.dedupe: + self._last_sent[field] = value + msg = VmixMessage(field, str(value)) + try: + self.queue.put_nowait(msg) + except Exception: + # Сбрасываем самое старое сообщение, чтобы не накапливать задержку + try: + _ = self.queue.get_nowait() + self.queue.task_done() + except Empty: + pass + self.queue.put_nowait(msg) + + def _run(self): + while not self.stop_event.is_set(): + try: + msg = self.queue.get(timeout=0.01) + except Empty: + continue + t = VMIX_TARGETS[msg.field] + ok = self.client.call(t["Function"], t["Input"], msg.value, t.get("SelectedName"), t.get("SelectedIndex")) + if self.verbose: + if ok: + print(f"[vMix] {msg.field} <- {msg.value}") + else: + print(f"[vMix] ERROR send {msg.field} <- {msg.value}") + self.queue.task_done() + +# ---------------- Parser ---------------- +_QUARTER_RE = re.compile(r"\s([1-5])\s\s\d{6}\s") + +def parse_time_5ch(chunk: str) -> Optional[str]: + if len(chunk) != 5: + return None + try: + if chunk[0:2] == "0 " or chunk[0:2] == " ": + print(f"{int(chunk[1:3])}:{int(chunk[3:5]):02d}") + return f"{int(chunk[1:3])}:{int(chunk[3:5]):02d}" + else: + return f"{int(chunk[1:3])}.{chunk[3]}" + except Exception: + return None + +def format_shot_clock_from_tail_number(n: str) -> str: + tail = n[-2:] + if tail == "30": + return "" # не обновлять + num = n[:2] + word_to_int = "ABCDEFGHI@" + if n[1] in word_to_int: + return f"{num[0]}.{word_to_int.index(num[1])+1 if num[1] != '@' else '0'}" + else: + return num + +@dataclass +class ParsedPacket: + main_time: Optional[str] = None + score1: Optional[str] = None + score2: Optional[str] = None + quarter: Optional[str] = None + shot_clock: Optional[str] = None + +def parse_line(line: str, verbose: bool = False) -> Optional[ParsedPacket]: + clean = line.strip().replace("�", "") + if len(clean) != 52: + clean = clean[-52:] + print(clean) + if not clean or clean[0] not in ["3", "7", "8"]: + return None + + # фиксированные позиции — всегда + main_time_raw = clean[2:7] + main_time = parse_time_5ch(main_time_raw) + + # score1/score2 есть только если строка начинается с "3" + score1 = None + score2 = None + if clean and clean[0] == "3": + s1 = clean[7:10].strip() + s2 = clean[10:13].strip() + if s1: + score1 = s1 + if s2: + score2 = s2 + + # четверть — всегда, если найдётся + quarter = None + m = _QUARTER_RE.search(clean) + if m: + quarter = m.group(1) + + # шот-клок — всегда, если хвост — число + shot_clock = None + tail = clean[-5:] + shot_clock = format_shot_clock_from_tail_number(tail) + + return ParsedPacket( + main_time=main_time, + score1=score1, + score2=score2, + quarter=quarter, + shot_clock=shot_clock, + )# ---------------- Serial reader ---------------- +EOLS = {"CR": b"\r", "LF": b"\n", "CRLF": b"\r\n"} + + +def sniff_eol(sample: bytes) -> bytes: + if b"\r\n" in sample: + return EOLS["CRLF"] + if b"\r" in sample and b"\n" not in sample: + return EOLS["CR"] + if b"\n" in sample: + return EOLS["LF"] + return EOLS["CR"] + +class SerialReader: + def __init__( + self, + port: str, + baud: int, + newline: str, + strip_ws: bool, + sender: VmixSender, + send_quarter: bool, + autoeol: bool, + bytesize: int, + parity: str, + stopbits: float, + rtscts: bool, + xonxoff: bool, + dsrdtr: bool, + read_timeout: float = 0.03, + idle_flush: float = 0.06, + max_chunk: int = 512, + verbose: bool = False, + ): + self.port = port + self.baud = baud + self.eol = EOLS.get(newline.upper(), b"\r") + self.strip_ws = strip_ws + self.sender = sender + self.send_quarter = send_quarter + self.autoeol = autoeol + self.bytesize = bytesize + self.parity = getattr(serial, f"PARITY_{parity.upper()}", serial.PARITY_NONE) + self.stopbits = {1: serial.STOPBITS_ONE, 1.5: serial.STOPBITS_ONE_POINT_FIVE, 2: serial.STOPBITS_TWO}[stopbits] + self.rtscts = rtscts + self.xonxoff = xonxoff + self.dsrdtr = dsrdtr + self.read_timeout = max(0.0, float(read_timeout)) + self.idle_flush = max(0.0, float(idle_flush)) + self.max_chunk = max(1, int(max_chunk)) + self.verbose = verbose + + def run(self): + while True: + try: + with serial.Serial( + self.port, + baudrate=self.baud, + timeout=self.read_timeout, # КЛЮЧЕВОЕ: неблокирующее чтение + write_timeout=0.01, + bytesize=self.bytesize, + parity=self.parity, + stopbits=self.stopbits, + rtscts=self.rtscts, + xonxoff=self.xonxoff, + dsrdtr=self.dsrdtr, + ) as ser: + # if self.verbose: + # print( + # f"[serial] OPEN {ser.port} @ {self.baud} ({self.bytesize}{self._parity_name()}{self._stopbits_name()})" + # ) + try: + ser.setDTR(True) + ser.setRTS(True) + except Exception: + pass + ser.reset_input_buffer() + ser.reset_output_buffer() + + buffer = bytearray() + last_feed = time.time() + + # Авто-детект EOL: быстрый сэмпл + if self.autoeol: + sample_t0 = time.time() + while time.time() - sample_t0 < 0.15: # ~150 мс + n = ser.in_waiting + if n: + chunk = ser.read(min(n, self.max_chunk)) + if chunk: + buffer.extend(chunk) + if buffer: + self.eol = sniff_eol(buffer) + if self.verbose: + print(f"[serial] auto EOL = {self._eol_name(self.eol)}") + break + + while True: + n = ser.in_waiting + if n: + chunk = ser.read(min(n, self.max_chunk)) + else: + # читаем «минимум 1 байт», чтобы не спиниться + chunk = ser.read(1) + + if chunk: + buffer.extend(chunk) + last_feed = time.time() + + progressed = False + while True: + idx = buffer.find(self.eol) + if idx == -1: + break + line = buffer[:idx] + del buffer[: idx + len(self.eol)] + text = self._decode(line, self.strip_ws) + if text: + self._process(text) + progressed = True + + # Если нет EOL и давно не приходили байты — отдаём накопленное + if not progressed and buffer and (time.time() - last_feed) >= self.idle_flush: + text = self._decode(buffer, self.strip_ws) + buffer.clear() + if text: + self._process(text) + + except SerialException as e: + if self.verbose: + print(f"[serial] ERROR open/read {self.port}: {e}. Retry in 0.5s...") + time.sleep(0.5) + except KeyboardInterrupt: + if self.verbose: + print("\n[serial] Stopped by user.") + return + except Exception as e: + if self.verbose: + print(f"[serial] UNEXPECTED: {e}. Retry in 0.5s...") + time.sleep(0.5) + + def _decode(self, raw: bytes, strip_ws: bool) -> Optional[str]: + try: + text = raw.decode("utf-8", errors="replace") + except Exception: + text = raw.decode("latin-1", errors="replace") + if strip_ws: + text = text.strip() + return text or None + + def _process(self, text: str): + pkt = parse_line(text, verbose=self.verbose) + if not pkt: + if self.verbose: + print(f"[serial] RAW: {text!r}") + return + if pkt.main_time is not None: + self.sender.send("main_time", pkt.main_time) + if pkt.score1 is not None: + self.sender.send("score_1", pkt.score1) + if pkt.score2 is not None: + self.sender.send("score_2", pkt.score2) + if self.send_quarter and pkt.quarter is not None: + self.sender.send("quarter", pkt.quarter) + if pkt.shot_clock is not None: + self.sender.send("shot_clock", pkt.shot_clock) + + def _parity_name(self): + return {"N": "N", "E": "E", "O": "O", "M": "M", "S": "S"}[self.parity] + + def _stopbits_name(self): + return { + serial.STOPBITS_ONE: "1", + serial.STOPBITS_ONE_POINT_FIVE: "1.5", + serial.STOPBITS_TWO: "2", + }[self.stopbits] + + def _eol_name(self, e: bytes): + return {b"\r": "CR", b"\n": "LF", b"\r\n": "CRLF"}.get(e, f"{e!r}") + + +# ---------------- Probe (sniffer) ---------------- + +def probe_port(port: str, baud: int, seconds: int, **kwargs): + print("[probe] Available ports:") + for p in list_ports.comports(): + print(f" - {p.device}: {p.description}") + try: + with serial.Serial(port, baudrate=baud) as ser: + print(f"[probe] OPEN {ser.port} @ {baud}. Sniffing {seconds}s...") + ser.reset_input_buffer() + t0 = time.time() + total = 0 + while time.time() - t0 < seconds: + b = ser.read(512) + if not b: + continue + total += len(b) + print(f"[{len(b):03d} bytes] HEX: {b.hex(' ')}") + try: + txt = b.decode("utf-8") + except Exception: + txt = b.decode("latin-1", errors="replace") + print(f" TXT: {txt!r}") + print(f"[probe] Done. Total bytes: {total}") + except Exception as e: + print(f"[probe] ERROR: {e}") + + +# ---------------- CLI ---------------- + +def main(): + ap = argparse.ArgumentParser(description="COM -> vMix bridge (optimized)") + ap.add_argument("--port", required=True, help="e.g. COM2 or /dev/ttyUSB0") + ap.add_argument("--baud", type=int, default=19200) + ap.add_argument("--newline", choices=["LF", "CRLF", "CR"], default="CR") + ap.add_argument("--autoeol", action="store_true", help="Auto-detect EOL from stream") + ap.add_argument("--no-strip", action="store_true") + ap.add_argument("--vmix-host", default=VMIX_HOST) + ap.add_argument("--timeout", type=float, default=0.01) + ap.add_argument("--retries", type=int, default=2) + ap.add_argument("--backoff", type=float, default=0.2) + ap.add_argument("--dedupe", action="store_true", help="Deduplicate values before sending to vMix") + ap.add_argument("--send-quarter", action="store_true") + ap.add_argument("--read-timeout", type=float, default=0.03, help="Serial read timeout (s)") + ap.add_argument("--idle-flush", type=float, default=0.06, help="Flush partial line after idle (s)") + ap.add_argument("--max-chunk", type=int, default=512, help="Max bytes per read()") + ap.add_argument("--verbose", action="store_true") + # serial low-level + ap.add_argument("--bytesize", type=int, choices=[5, 6, 7, 8], default=8) + ap.add_argument("--parity", choices=["N", "E", "O", "M", "S"], default="N") + ap.add_argument("--stopbits", type=float, choices=[1, 1.5, 2], default=1) + ap.add_argument("--rtscts", action="store_true") + ap.add_argument("--xonxoff", action="store_true") + ap.add_argument("--dsrdtr", action="store_true") + # tools + ap.add_argument("--probe", type=int, metavar="SECONDS", help="Sniff raw bytes/text for N seconds and exit") + args = ap.parse_args() + + if args.probe: + probe_port(args.port, args.baud, args.probe) + return + + client = VmixClient(host=args.vmix_host, timeout=args.timeout, retries=args.retries, backoff=args.backoff) + sender = VmixSender(client=client, dedupe=args.dedupe or True, verbose=args.verbose) + sender.start() + + reader = SerialReader( + port=args.port, + baud=args.baud, + newline=args.newline, + strip_ws=not args.no_strip, + sender=sender, + send_quarter=args.send_quarter, + autoeol=args.autoeol, + bytesize=args.bytesize, + parity=args.parity, + stopbits=args.stopbits, + rtscts=args.rtscts, + xonxoff=args.xonxoff, + dsrdtr=args.dsrdtr, + read_timeout=args.read_timeout, + idle_flush=args.idle_flush, + max_chunk=args.max_chunk, + verbose=args.verbose, + ) + try: + reader.run() + finally: + sender.stop() + + +if __name__ == "__main__": + main() diff --git a/timer GPT 1.py b/timer GPT 1.py new file mode 100644 index 0000000..5a39d21 --- /dev/null +++ b/timer GPT 1.py @@ -0,0 +1,117 @@ +# serial_to_vmix.py +# pip install pyserial requests + +import time +import argparse +import socket +import urllib.parse +import requests +import serial +from serial.serialutil import SerialException + +# --------------------------- +# 1) ВАША функция отправки в vMix +# Замените содержимое по своему желанию. +# --------------------------- +def parse(data: str): + """ + Пользовательская обработка/отправка данных в vMix. + Здесь просто печатаем; замените на вашу логику. + """ + print(f"[parse] {data}") + +# ---- ПРИМЕРЫ реализации parse (раскомментируйте нужное) ---- +# Пример A: отправка через vMix HTTP API (SetText в определённый input/title) +# def parse(data: str): +# vmix_host = "http://127.0.0.1:8088" # адрес vMix Web Controller +# function = "SetText" +# input_id = "1" # замените на ваш Input (номер/имя/строка GUID) +# selected_title = None # если нужно указать конкретный Title layer: "TitleName.xaml" +# field = None # если нужно указать конкретное текстовое поле в титре +# +# params = { +# "Function": function, +# "Input": input_id, +# "Value": data +# } +# if selected_title: +# params["SelectedName"] = selected_title +# if field: +# params["SelectedIndex"] = field +# +# # важно: корректно кодируем Value +# url = f"{vmix_host}/api?{urllib.parse.urlencode(params, doseq=True, safe='')}" +# try: +# r = requests.get(url, timeout=2) +# r.raise_for_status() +# except requests.RequestException as e: +# print(f"[parse][HTTP] ошибка запроса к vMix: {e}") + +# Пример B: отправка одной строки в vMix TCP (порт 8099) — например, выполнить функцию +# def parse(data: str): +# vmix_tcp_host = "127.0.0.1" +# vmix_tcp_port = 8099 +# # пример: выполнить SetText +# cmd = f"FUNCTION SetText Input=1 Value=\"{data}\"\r\n" +# try: +# with socket.create_connection((vmix_tcp_host, vmix_tcp_port), timeout=2) as s: +# s.sendall(cmd.encode("utf-8")) +# except OSError as e: +# print(f"[parse][TCP] ошибка сокета к vMix: {e}") + +# --------------------------- +# 2) Чтение из COM-порта и вызов parse +# --------------------------- +def read_loop(port: str, baud: int, newline: str, strip_whitespace: bool): + # мапинг для окончания строк в pyserial + eol = {"CRLF": b"\r\n", "LF": b"\n", "CR": b"\r"}.get(newline.upper(), b"\n") + + while True: + try: + with serial.Serial(port, baudrate=baud, timeout=1) as ser: + print(f"[serial] открыт {ser.port} @ {baud} бод. Ожидаю данные...") + buffer = bytearray() + while True: + chunk = ser.read(1024) + if not chunk: + continue + buffer.extend(chunk) + # разбираем по разделителю строк + while True: + idx = buffer.find(eol) + if idx == -1: + break + line = buffer[:idx] + del buffer[:idx + len(eol)] + try: + text = line.decode("utf-8", errors="replace") + except Exception: + text = line.decode("latin-1", errors="replace") + if strip_whitespace: + text = text.strip() + if text != "": + parse(text) + except SerialException as e: + print(f"[serial] не удалось открыть/читать {port}: {e}. Повтор через 3 сек...") + time.sleep(3) + except KeyboardInterrupt: + print("\n[serial] остановлено пользователем.") + break + except Exception as e: + print(f"[serial] непредвиденная ошибка: {e}. Повтор через 3 сек...") + time.sleep(3) + +def main(): + ap = argparse.ArgumentParser(description="Чтение COM и отправка в vMix через parse()") + ap.add_argument("--port", required=True, help="COM-порт, напр. COM3 (Windows) или /dev/ttyUSB0 (Linux)") + ap.add_argument("--baud", type=int, default=19200, help="Скорость, по умолчанию 9600") + ap.add_argument("--newline", choices=["LF", "CRLF", "CR"], default="CR", + help="Разделитель строк, по умолчанию LF") + ap.add_argument("--no-strip", action="store_true", + help="Не обрезать пробелы по краям (по умолчанию обрезаем)") + args = ap.parse_args() + + read_loop(args.port, args.baud, args.newline, strip_whitespace=not args.no_strip) + +if __name__ == "__main__": + main() diff --git a/timer NATA Kazan.py b/timer NATA Kazan.py new file mode 100644 index 0000000..d7e26bb --- /dev/null +++ b/timer NATA Kazan.py @@ -0,0 +1,189 @@ +import sys +import json +from socket import * +from datetime import datetime +import logging +import os +import time +import binascii +import requests + + +HOST = "192.168.127.254" +PORT = 1993 +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + +session = requests.Session() +session.headers.update({"Connection": "keep-alive"}) + + +def hexspace(string, length): + return " ".join(string[i : i + length] for i in range(0, len(string), length)) + + +def send_data(name, value): + url = "http://127.0.0.1:8088/API/" + par = "SetText" if name.split(".")[1] == "Text" else "SetImage" + params = { + "Function": par, + "Input": 33, + "SelectedName": name, + "Value": value, + } + session.get(url, params=params) + +def parse_new(line): + try: + with open(PATH, "r", encoding="utf-8") as f: + new_data = json.load(f) + except json.decoder.JSONDecodeError: + new_data = [ + { + "timeGFX": "0:00", + "time_attackGFX": "", + "quarter": "0", + "points1": "0", + "points2": "0", + "foul1": "0", + "foul2": "0", + "foul_pic1": "", + "foul_pic2": "", + "time_attac_pic": "", + "timeout1": "0", + "timeout2": "0", + } + ] + + cdata = binascii.hexlify(line) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + temp = edata.split("FF 52") + # print(temp) + for i in temp: + if "7D 4A C0 0A" in i: #основной таймер + minutes = int(i.split()[-5], ) + seconds = int(i.split()[-4], ) + milliseconds = int(i.split()[-3], ) + timer_str = ( + f"{minutes}:{seconds:02d}" if minutes != 0 else f"{seconds}.{milliseconds}" + ) + send_data("TIMER.Text", timer_str) + + # print(i.split()[-7], i) + # if i.split()[-7] == "13" or i.split()[-7] == "10": + # new_data[0]["timeGFX"] = timer_str + elif "7D 4A C0 07" in i: #Счет + if i.split()[-7] == "06": #Счет первой команды + score1 = int(i.split()[-4], 16) + # new_data[0]["points1"] = score1 + send_data("SCORE1.Text", score1) + elif i.split()[-7] == "07": #Счет второй команды + score2 = int(i.split()[-4], 16) + send_data("SCORE2.Text", score2) + # new_data[0]["points2"] = score2 + else: + print("[СЧЁТ] == НЕПОНЯТНО") + elif "7D 4A C0 06" in i: #Информация + if i.split()[-6] == "09": #фолы первой команды + foul1 = int(i.split()[-3], 16) + # new_data[0]["foul1"] = foul1 + send_data("fouls1.Source", f"D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\Away_{foul1}.png") + elif i.split()[-6] == "0A": #фолы второй команды + foul2 = int(i.split()[-3], 16) + send_data("fouls2.Source", f"D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\Away_{foul2}.png") + # new_data[0]["foul2"] = foul2 + elif i.split()[-6] == "0E": #тайм-аут первой команды + time_out1 = int(i.split()[-3], 16) + # new_data[0]["timeout1"] = time_out1 + elif i.split()[-6] == "0F": #тайм-аут второй команды + time_out2 = int(i.split()[-3], 16) + # new_data[0]["timeout2"] = time_out2 + elif i.split()[-6] == "08": #четверть + quarter = int(i.split()[-3], 16) + # new_data[0]["quarter"] = quarter + + elif "79 84 C0 0A" in i: #24 секунды + print(i) + seconds = int(i.split()[-4]) + milliseconds = int(i.split()[-3]) + if seconds < int(5): + time_attack = f"{seconds}.{milliseconds}" + timer_pic = "D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\24Sec_Red.png" + else: + time_attack = seconds + timer_pic = "D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\24Sec_Empty.png" + if time_attack == "0.0": + time_attack = "" + timer_pic = "D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\24Sec_Empty.png" + send_data("24sec.Text", time_attack) + # send_data("24SECBACKGROUND.Source", timer_pic) + + # print(time_attack) + elif "89 4E C8 05" in i: + if i.split()[-3] == "05": #таймер 24 секунд выключен + time_attack = "" + timer_pic = "D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\24Sec_Empty.png" + send_data("24sec.Text", time_attack) + # send_data("24SECBACKGROUND.Source", timer_pic) + # data = { + # "TIMER.Text": timer_str, + # "ATTACK.Text": time_attack, + # "Score_Home.Text": score1, + # "Score_Away.Text": score2, + # "fouls1.Source": f"D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\Home_{foul1}.png", + # "fouls2.Source": f"D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\Away_{foul2}.png", + # "24SECBACKGROUND.Source": timer_pic, + # } + +def read_logs(): + with open( + r"C:\Users\soule\Downloads\Telegram Desktop\timer_Megasport_Nport_2024-03-05_20-00-17.log", + "r", + ) as file: + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = eval(parts[1]) + if b"\xf83" in data or b"\xf88" in data or b"\xf87" in data: + parse(data) + time.sleep(0.1) + + +def main(): + current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_Nata_Nport_{current_time}.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + parse_new(data) + logging.debug(data) + + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + # read_logs() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_KAZ.py b/timer_KAZ.py new file mode 100644 index 0000000..5e511f5 --- /dev/null +++ b/timer_KAZ.py @@ -0,0 +1,162 @@ +import sys +import json +from socket import * +from datetime import datetime +import time +import os +# import logging + + +VERSION = "версия 2" # от 02.04.2024 + +host = "192.168.127.254" +port = 1993 +ADDR = (host, port) +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + + +def save_log(name, data): + current_time = datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f") + message_with_time = f"[{current_time}] {data}" + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + with open(f"LOGS/{name}", "a") as file: + file.write(message_with_time + "\n") + + +def parse(data, score1, score2): + data = data.split("/") + + with open(PATH, "r", encoding="utf-8") as f: + new_data = json.load(f) + new_data = new_data[0] + path_pic = r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators" + # print(data) + diff1, diff2 = 0, 0 + try: + if len(data) > 10: + if data[4] == "NPR": + new_data["quarter"] = data[5] + if data[17] == "HCP": + new_data["points1"] = data[18] + if score1 != new_data["points1"]: + diff1 = int(new_data["points1"]) - int(score1) + score1 = new_data["points1"] + if data[20] == "GCP": + new_data["points2"] = data[21] + if score2 != new_data["points2"]: + diff2 = int(new_data["points2"]) - int(score2) + score2 = new_data["points2"] + if data[29] == "HCF": + new_data["foul1"] = data[30] + new_data["foul_pic1"] = path_pic + f"\\Home_{int(data[30])}.png" + if data[32] == "GCF": + new_data["foul2"] = data[33] + new_data["foul_pic2"] = path_pic + f"\\Away_{int(data[33])}.png" + else: + if data[1] == "TGI": + if data[2] != "0": + seconds = data[3] if len(data[3]) != 1 else f"0{data[3]}" + new_data["timeGFX"] = f"{data[2]}:{seconds}" + else: + millisec = data[4] + if not millisec.isdigit(): + millisec = "0" + new_data["timeGFX"] = f"{data[3]}.{millisec}" + elif data[1] == "NPR": + new_data["quarter"] = data[2] + elif data[1] == "HCP": + new_data["points1"] = data[2] + if score1 != new_data["points1"]: + diff1 = int(new_data["points1"]) - int(score1) + score1 = new_data["points1"] + elif data[1] == "GCP": + new_data["points2"] = data[2] + if score2 != new_data["points2"]: + diff2 = int(new_data["points2"]) - int(score2) + score2 = new_data["points2"] + elif data[1] == "HCF": + new_data["foul1"] = data[2] + new_data["foul_pic1"] = path_pic + f"\\Home_{int(data[2])}.png" + if len(data) > 4 and data[4] == "GCF": + new_data["foul2"] = data[2] + new_data["foul_pic2"] = path_pic + f"\\Away_{int(data[2])}.png" + elif data[1] == "GCF": + new_data["foul2"] = data[2] + new_data["foul_pic2"] = path_pic + f"\\Away_{int(data[2])}.png" + elif data[1] == "TAI": + if data[2] not in ["0", "-1"]: + new_data["time_attackGFX"] = str(int(data[2])) + elif data[2] == "-1": + new_data["time_attackGFX"] = "" + new_data["time_attac_pic"] = path_pic + "\\24Sec_empty.png" + if 0 < int(data[2]) <= 5: + new_data["time_attac_pic"] = path_pic + "\\24Sec_Red.png" + else: + if int(data[2]) in [0, -1]: + new_data["time_attac_pic"] = path_pic + "\\24Sec_empty.png" + else: + new_data["time_attac_pic"] = path_pic + "\\24Sec_Orange.png" + + print(f'{diff1}, {diff2}, {new_data["timeGFX"]:<5}, {new_data["time_attackGFX"]:<3}, {new_data["points1"]:<3}, {new_data["points2"]:<3}, {new_data["foul1"]:<2}, {new_data["foul2"]:<2}') + except Exception as ex: + print(ex) + try: + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + # if ":" in new_data["timeGFX"]: + # time.sleep(.5) + # else: + # time.sleep(.1) + + except Exception: + pass + + return score1, score2 + + +def main(): + current_time = datetime.now().strftime("%d-%m-%Y_%H-%M-%S") + + new_data = { + "timeGFX": "0:00", + "time_attackGFX": "", + "quarter": "0", + "points1": "0", + "points2": "0", + "foul1": "0", + "foul2": "0", + "foul_pic1": "", + "foul_pic2": "", + "time_attac_pic": "", + } + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect(ADDR) + score1, score2 = 0, 0 + + try: + while True: + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + data = tcp_socket.recv(1024) + data = data.decode("utf-8", errors="ignore") + print(data) + + save_log(f"logs_mba_{VERSION}_{current_time}.txt", data) + score1, score2 = parse(data, score1, score2) + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_MBA.py b/timer_MBA.py new file mode 100644 index 0000000..89b9c2c --- /dev/null +++ b/timer_MBA.py @@ -0,0 +1,208 @@ +import sys +import json +from socket import * +from datetime import datetime +import time +import os +# import logging +import requests + + +VERSION = "версия 2" # от 02.04.2024 + +host = "10.0.0.57" +port = 50002 +ADDR = (host, port) +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + +session = requests.Session() +session.headers.update({"Connection": "keep-alive"}) + +def save_log(name, data): + current_time = datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f") + message_with_time = f"[{current_time}] {data}" + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + with open(f"LOGS/{name}", "a") as file: + file.write(message_with_time + "\n") + + +def send_data(name, value): + url = "http://127.0.0.1:8088/API/" + par = "SetText" if name.split(".")[1] == "Text" else "SetImage" + params = { + "Function": par, + "Input": 41, + # "Input": "SCOREBUG", + "SelectedName": name, + "Value": value, + } + session.get(url, params=params) + + +def parse(data, score1, score2): + data = data.split("/") + + with open(PATH, "r", encoding="utf-8") as f: + new_data = json.load(f) + new_data = new_data[0] + path_pic = r"D:\графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ ФИНАЛ ЧЕТЫРЕХ\FOULS" + # print(data) + diff1, diff2 = 0, 0 + if len(data) > 10: + if data[4] == "NPR": + new_data["quarter"] = data[5] + if data[17] == "HCP": + new_data["points1"] = data[18] + if score1 != new_data["points1"]: + diff1 = int(new_data["points1"]) - int(score1) + score1 = new_data["points1"] + if data[20] == "GCP": + new_data["points2"] = data[21] + if score2 != new_data["points2"]: + diff2 = int(new_data["points2"]) - int(score2) + score2 = new_data["points2"] + if data[29] == "HCF": + new_data["foul1"] = data[30] + new_data["foul_pic1"] = path_pic + f"\\FOULS_{int(data[30])}.png" + if data[32] == "GCF": + new_data["foul2"] = data[33] + new_data["foul_pic2"] = path_pic + f"\\FOULS_{int(data[33])}.png" + else: + if data[1] == "TGI": + if data[2] != "0": + seconds = data[3] if len(data[3]) != 1 else f"0{data[3]}" + new_data["timeGFX"] = f"{data[2]}:{seconds}" + else: + millisec = data[4] + if not millisec.isdigit(): + millisec = "0" + new_data["timeGFX"] = f"{data[3]}.{millisec}" + elif data[1] == "NPR": + new_data["quarter"] = data[2] + elif data[1] == "HCP": + new_data["points1"] = data[2] + if score1 != new_data["points1"]: + diff1 = int(new_data["points1"]) - int(score1) + score1 = new_data["points1"] + elif data[1] == "GCP": + new_data["points2"] = data[2] + if score2 != new_data["points2"]: + diff2 = int(new_data["points2"]) - int(score2) + score2 = new_data["points2"] + elif data[1] == "HCF": + new_data["foul1"] = data[2] + new_data["foul_pic1"] = path_pic + f"\\FOULS_{int(data[2])}.png" + if len(data) > 4 and data[4] == "GCF": + new_data["foul2"] = data[2] + new_data["foul_pic2"] = path_pic + f"\\FOULS_{int(data[2])}.png" + elif data[1] == "GCF": + new_data["foul2"] = data[2] + new_data["foul_pic2"] = path_pic + f"\\FOULS_{int(data[2])}.png" + elif data[1] == "TAI": + if data[2] not in ["0", "-1"]: + new_data["time_attackGFX"] = str(int(data[2])) + elif data[2] == "-1": + new_data["time_attackGFX"] = "" + new_data["time_attac_pic"] = path_pic + "\\24Sec_empty.png" + if 0 < int(data[2]) <= 5: + new_data["time_attac_pic"] = path_pic + "\\24Sec_Red.png" + else: + if int(data[2]) in [0, -1]: + new_data["time_attac_pic"] = path_pic + "\\24Sec_empty.png" + else: + new_data["time_attac_pic"] = path_pic + "\\24Sec_Orange.png" + send_data("Timer.Text", new_data["timeGFX"]) + send_data("Score_Team1.Text", new_data["points1"]) + send_data("Score_Team2.Text", new_data["points2"]) + send_data("Timer24sec.Text", new_data["time_attackGFX"]) + send_data("FOULS_TEAM_A.Source", new_data["foul_pic1"]) + send_data("FOULS_TEAM_B.Source", new_data["foul_pic2"]) + + print(f'{diff1}, {diff2}, {new_data["timeGFX"]:<5}, {new_data["time_attackGFX"]:<3}, {new_data["points1"]:<3}, {new_data["points2"]:<3}, {new_data["foul1"]:<2}, {new_data["foul2"]:<2}') + try: + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + # if ":" in new_data["timeGFX"]: + # time.sleep(.5) + # else: + # time.sleep(.1) + + except Exception: + pass + + return score1, score2 + + +def read_logs(): + score1, score2 = 0, 0 + new_data = { + "timeGFX": "0:00", + "time_attackGFX": "", + "quarter": "0", + "points1": "0", + "points2": "0", + "foul1": "0", + "foul2": "0", + "foul_pic1": "", + "foul_pic2": "", + "time_attac_pic": "", + } + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + with open("D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\logs_mba_3.txt", "r") as file: + for line in file: + parts = line.strip().split("] ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = parts[1] + score1, score2 = parse(data, score1, score2) + time.sleep(.1) + + +def main(): + current_time = datetime.now().strftime("%d-%m-%Y_%H-%M-%S") + + new_data = { + "timeGFX": "0:00", + "time_attackGFX": "", + "quarter": "0", + "points1": "0", + "points2": "0", + "foul1": "0", + "foul2": "0", + "foul_pic1": "", + "foul_pic2": "", + "time_attac_pic": "", + } + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect(ADDR) + score1, score2 = 0, 0 + + try: + while True: + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + data = tcp_socket.recv(1024) + data = data.decode("utf-8", errors="ignore") + print(data) + + save_log(f"logs_mba_{VERSION}_{current_time}.txt", data) + score1, score2 = parse(data, score1, score2) + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + # read_logs() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_NN.py b/timer_NN.py new file mode 100644 index 0000000..887eedc --- /dev/null +++ b/timer_NN.py @@ -0,0 +1,171 @@ +import sys +import json +from socket import * +from datetime import datetime +import logging +import os +import time +import binascii +import requests + +HOST = "192.168.0.7" +PORT = 40004 +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + +session = requests.Session() +session.headers.update({"Connection": "keep-alive"}) + + +def hexspace(string, length): + return " ".join(string[i : i + length] for i in range(0, len(string), length)) + + +def timer(line): + temp_new = [int(t, 16) for t in line.split()] + minutes = temp_new[4] + seconds = temp_new[5] + milliseconds = temp_new[6] + timer_str = ( + f"{minutes}:{seconds:02d}" if minutes != 0 else f"{seconds}.{milliseconds}" + ) + return timer_str + + +def attack_time(line): + temp_new = [int(t, 16) for t in line.split()] + path_pic = r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators" + if temp_new[7] != 2: + seconds = temp_new[5] + milliseconds = temp_new[6] + if int(seconds) > 4: + if int(milliseconds) >= 5: + seconds = int(seconds) + 1 + else: + seconds = seconds + time_attack = seconds + else: + time_attack = f"{seconds}.{milliseconds}" + if time_attack == "0.0": + time_attack = "" + # time_attack = ( + # temp_new[5] + # if temp_new[5] > 4 + # else f"{temp_new[5]}.{temp_new[6]}" + # if f"{temp_new[5]}.{temp_new[6]}" != "0.0" + # else "" + # ) + path_pic = path_pic + ( + "\\24Sec_Orange.png" + if temp_new[5] > 4 + else ( + "\\24Sec_Red.png" + if f"{temp_new[5]}.{temp_new[6]}" != "0.0" + else "\\24Sec_empty.png" + ) + ) + else: + time_attack = "" # temp_new[-2] == 1 - таймер идёт | 2 - таймер стоит | 0 - таймер не отображён + path_pic = path_pic + "\\24Sec_empty.png" + return time_attack, path_pic + +def send_data(name, value): + url = "http://127.0.0.1:8088/API/" + par = "SetText" if name.split(".")[1] == "Text" else "SetImage" + params = { + "Function": par, + # "Input": 41, + "Input": "SCOREBUG", + "SelectedName": name, + "Value": value, + } + session.get(url, params=params) + +def parse(line): + cdata = binascii.hexlify(line) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + + temp_line = "" + line = "" + if len(edata.split()) in [2, 31, 32, 1]: + if temp_line == "": + temp_line = edata + else: + line = temp_line + edata + temp_line = "" + else: + line = edata + + data = line.split("FE FF") + path_pic_foul = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators" + ) + diff1, diff2 = 0, 0 + for d in data: + if d != "": + temp_d = d.strip() + if "08 01" in temp_d[:5] and str(temp_d.split()[-2])[0] == "8": + timer_str = timer(temp_d) + send_data("TIMER.Text", timer_str) + aaaaa = temp_d.split()[-2] + elif "08 03" in temp_d[:5]: + time_attack, path_pic = attack_time(temp_d) + send_data("24sec.Text", time_attack) + aaaa = temp_d.split()[-2], int(temp_d.split()[-2], 16) + elif "0D 1F" in temp_d[:5]: + send_data("SCORE1.Text", int(temp_d.split()[2], 16)) + send_data("SCORE2.Text", int(temp_d.split()[3], 16)) + + +def read_logs(): + + score1, score2 = 0, 0 + with open("timer_NN_1.log", "r") as file: + # with open("timer_NN_test.log", "r") as file: + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = eval(parts[1]) + parse(data) + time.sleep(0.1) + + +def main(): + current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_NN_{current_time}.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + print(data) + logging.debug(data) + parse(data) + + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + # read_logs() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_NN_backup.py b/timer_NN_backup.py new file mode 100644 index 0000000..2ff2b08 --- /dev/null +++ b/timer_NN_backup.py @@ -0,0 +1,159 @@ +import sys +import json +from socket import * +from datetime import datetime +import logging +import os +import time +import binascii + +HOST = "192.168.0.7" +PORT = 40004 +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + + +def hexspace(string, length): + return " ".join(string[i : i + length] for i in range(0, len(string), length)) + + +def parse(line): + with open(PATH, "r", encoding="utf-8") as f: + new_data = json.load(f) + cdata = binascii.hexlify(line) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + path_pic = r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators" + + if len(edata.split()) in [32, 33, 40]: + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + minutes = temp_new[6] + seconds = temp_new[7] + milliseconds = temp_new[8] + timer_str = ( + f"{minutes}:{seconds:02d}" + if minutes != 0 + else f"{seconds}.{milliseconds}" + ) + active_temp = temp_new[ + 9 + ] # 133 - таймер идёт | 132 - таймер стоит | 128 - не игровое время стоит | 129 - не игровое время идёт + + if temp_new[31] not in [2]: + time_attack = ( + temp_new[29] if temp_new[29] > 4 else f"{temp_new[29]}.{temp_new[30]}" if f"{temp_new[29]}.{temp_new[30]}" != "0.0" else "" + ) + path_pic = path_pic + ("\\24Sec_Orange.png" if temp_new[29] > 4 else "\\24Sec_Red.png" if f"{temp_new[29]}.{temp_new[30]}" != "0.0" else "\\24Sec_empty.png") + else: + time_attack = "" # temp_new[-2] == 1 - таймер идёт | 2 - таймер стоит | 0 - таймер не отображён + path_pic = path_pic + "\\24Sec_empty.png" + + # print(f"{str(temp_new):<120}__{timer_str:<7}__{time_attack:<3}__") + new_data[0]["timeGFX"] = timer_str + new_data[0]["time_attackGFX"] = time_attack + new_data[0]["time_attac_pic"] = path_pic + else: + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + timer_str = "99:99" + time_attack = "99:99" + + + print(len(edata.split()), f"{str(edata):<120}__{timer_str:<7}__{time_attack:<3}__") + + + try: + with open(PATH, "w", encoding="utf-8") as file: + json.dump(new_data, file, ensure_ascii=False, indent=4) + # if ":" in new_data["timeGFX"]: + # time.sleep(.5) + # else: + # time.sleep(.1) + + except Exception: + pass + + + # with open("timer_NN.csv", "a+") as file: + # file.write(str(temp_new)) + # file.write("\n") + # with open("timer_NN_2.csv", "a+") as file: + # file.write(str(temp_data)) + # file.write("\n") + # with open("timer_NN_3.csv", "a+") as file: + # file.write(str(ddata)) + # file.write("\n") + + # time.sleep(0.1) + + +def read_logs(): + with open("timer_NN_1.log", "r") as file: + # with open("timer_NN_test.log", "r") as file: + temp_line = "" + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = eval(parts[1]) + parse(data) + time.sleep(.05) + + # if len(eval(data)) > 30 and eval(data)[-7] == "00": + # time.sleep(.1) + # else: + # time.sleep(1) + + +def main(): + current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_NN_{current_time}.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + new_data = { + "timeGFX": "0:00", + "time_attackGFX": "", + "quarter": "0", + "points1": "0", + "points2": "0", + "foul1": "0", + "foul2": "0", + "foul_pic1": "", + "foul_pic2": "", + "time_attac_pic": "", + } + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + print(data) + logging.debug(data) + parse(data) + + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + # main() + read_logs() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_NPORT_Deepron.py b/timer_NPORT_Deepron.py new file mode 100644 index 0000000..d1ffd54 --- /dev/null +++ b/timer_NPORT_Deepron.py @@ -0,0 +1,153 @@ +import sys +from socket import * +from datetime import datetime +import logging +import os +import time +import requests + + +SETTING = "9600,RS-232" +HOST = "192.168.127.254" +PORT = 1993 +URL = "http://127.0.0.1:8088/API/" +INPUT = ["ТАЙМЕР МУЖЧИНЫ", "ТАЙМЕР ЖЕНЩИНЫ"] + + +def send_data(data, name): + for i in INPUT: + params = { + "Function": "SetText", + "Input": i, + "SelectedName": f"{name}.Text", + "Value": data, + } + requests.get(URL, params=params) + + +def win(name): + params = { + "Function": "SetTextColour", + "Input": INPUT, + "SelectedName": f"{name}.Text", + "Value": "Green", + } + requests.get(URL, params=params) + + +def reset(name): + params = { + "Function": "SetTextColour", + "Input": INPUT, + "SelectedName": f"{name}.Text", + "Value": "white", + } + requests.get(URL, params=params) + + +def func_new(i, name, tag): + data = ( + i.split(f"{tag}<")[1] + .replace("0'0", "") + .replace("0'", "") + .replace("10>", "") + .split()[0] + ) + if "FALSE START" in i: + send_data("FS", name) + elif "OK NO FS" in i: + pass + else: + send_data(data, name) + # if "WIN" in i: + # win(name) + + +def parse(line): + decode_line = line.decode("utf-8") + print(decode_line) + temp_list = decode_line.split("") + name1, name2, name3, name4 = "Time1", "Time2", "Reaction1", "Reaction2" + for i in temp_list: + if i != "": + if "READY" in i: + send_data('0"000', name1) + send_data('0"000', name2) + send_data("", name3) + send_data("", name4) + # reset(name1) + # reset(name2) + + if not any(char in i[7] for char in ["R", "G", "B", "C", "Y", "M", "A"]): + if "" in i and not any(char in i for char in ["$", "@", "%"]): + func_new(i, name1, "") + elif "" in i and not any(char in i for char in ["$", "@", "%"]): + func_new(i, name2, "") + elif "" in i: + func_new(i, name3, "") + elif "" in i: + func_new(i, name4, "") + + +def read_logs(): + with open("C:\Code\LOGS\\timer_NPORT_tcp_2024-03-29_13-24-22.log", "r") as file: + timestamp_temp = "" + diff_time = 0 + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0] + if timestamp_temp == "": + timestamp_temp = timestamp + else: + time_format = "%Y-%m-%d %H:%M:%S,%f" + timestamp_datetime = datetime.strptime(timestamp, time_format) + timestamp_temp_datetime = datetime.strptime( + timestamp_temp, time_format + ) + delta = timestamp_datetime - timestamp_temp_datetime + seconds = delta.total_seconds() # Convert timedelta to seconds + timestamp_temp = timestamp + time.sleep(abs(seconds - diff_time)) + data = eval(parts[1]) + start_time = time.time() + parse(data) + end_time = time.time() + diff_time = end_time - start_time + + +def main(): + current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_NPORT_tcp_{current_time}.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + logging.debug(data) + parse(data) + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + # while True: + # read_logs() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_NPORT_коньки.py b/timer_NPORT_коньки.py new file mode 100644 index 0000000..590ce42 --- /dev/null +++ b/timer_NPORT_коньки.py @@ -0,0 +1,128 @@ +import sys +from socket import * +from datetime import datetime +import logging +import os +import time +import binascii +import requests + + +HOST = "192.168.127.254" +PORT = 1993 +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + + +def hexspace(string, length): + return " ".join(string[i : i + length] for i in range(0, len(string), length)) + + +def parse(line): + cdata = binascii.hexlify(line) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + + if len(edata.split()) == 33: + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + minutes = temp_new[6] + seconds = temp_new[7] + milliseconds = temp_new[8] + timer_str = ( + f"{minutes}:{seconds:02d}" + if minutes != 0 + else f"{seconds:02d}.{milliseconds}" + ) + active_temp = temp_new[ + 9 + ] # 133 - таймер идёт | 132 - таймер стоит | 128 - не игровое время стоит | 129 - не игровое время идёт + + if temp_new[-2] != 0: + time_attack = ( + temp_new[-4] if temp_new[-4] > 4 else f"{temp_new[-4]}.{temp_new[-3]}" + ) + else: + time_attack = "" # temp_new[-2] == 1 - таймер идёт | 2 - таймер стоит | 0 - таймер не отображён + + # print(f"{str(temp_new):<120}__{timer_str:<7}__{time_attack:<3}__") + else: + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + + # time.sleep(0.1) + + +def read_logs(): + with open("timer_NN_2023-12-20_18-17-29.log", "r") as file: + # with open("timer_NN_test.log", "r") as file: + temp_line = "" + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = eval(parts[1]) + parse(data) + time.sllep(0.1) + + # if len(eval(data)) > 30 and eval(data)[-7] == "00": + # time.sleep(.1) + # else: + # time.sleep(1) + + +def parse_2(data): + data = data.decode() + print(data) + if "S04" in data: + temp = data.split("S04")[1] + print(f"{data:<50}", temp) + elif "S09" in data: #White + temp = data + elif "S00" in data: #Red + temp = data + +def main(): + current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_NPORT_zzz_{current_time}.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + temp = b"" + line_new = b"" + while True: + data = tcp_socket.recv(1024) + logging.debug(data) + print(data) + if b"\x03" in data: + temp += data + line_new = temp + temp = b"" + else: + temp += data + + parse_2(line_new) + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_app.py b/timer_app.py new file mode 100644 index 0000000..34644d7 --- /dev/null +++ b/timer_app.py @@ -0,0 +1,92 @@ +import socket +import tkinter as tk +import threading +import re + + +def on_validate(P): + # Проверка на соответствие шаблону IP-адреса (допускаются промежуточные неполные значения) + pattern = ( + r"^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){0,3}" + r"(25[0-5]|2[0-4]\d|[01]?\d\d?)?$" + ) + return re.match(pattern, P) is not None + + +class ServerConnectionApp: + def __init__(self, root): + self.root = root + self.root.title("Server Connection App") + + # GUI setup + self.setup_gui() + + # Server connection + self.client_socket = None + + def setup_gui(self): + self.ip_label = tk.Label(self.root, text="IP Address:") + self.ip_label.grid(row=0, column=0) + + self.ip_entry = tk.Entry(self.root) + self.ip_entry.grid(row=0, column=1) + self.ip_entry.insert(0, "127.0.0.1") # Default IP address (localhost) + + self.port_label = tk.Label(self.root, text="Port:") + self.port_label.grid(row=1, column=0) + + self.port_entry = tk.Entry(self.root) + self.port_entry.grid(row=1, column=1) + self.port_entry.insert(0, "12345") # Default port + + self.connect_button = tk.Button(self.root, text="Connect", command=self.initiate_connection) + self.connect_button.grid(row=2, column=0, columnspan=2) + + self.status_label = tk.Label(self.root, text="") + self.status_label.grid(row=3, column=0, columnspan=2) + + def initiate_connection(self): + ip = self.ip_entry.get() + port = int(self.port_entry.get()) + + # Create a thread to avoid blocking the GUI + connection_thread = threading.Thread(target=self.connect_to_server, args=(ip, port)) + connection_thread.daemon = True + connection_thread.start() + + def connect_to_server(self, ip, port): + try: + self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.client_socket.connect((ip, port)) + self.status_label.config(text="Connected successfully.") + + # Consume the data and print it to the console + self.listen_to_server() + + except Exception as e: + self.status_label.config(text=f"Connection failed: {e}") + + def listen_to_server(self): + try: + while True: + data = self.client_socket.recv(1024) + if data: + print("Received from server:", data.decode()) + else: + # Connection is closed + print("Server has closed the connection.") + self.client_socket.close() + break + except Exception as e: + print(f"Error while listening to the server: {e}") + if self.client_socket: + self.client_socket.close() + +# Create the Tkinter window +root = tk.Tk() + +# Create an instance of the app +app = ServerConnectionApp(root) + +# Start the Tkinter main event loop +root.mainloop() \ No newline at end of file diff --git a/timer_app2.py b/timer_app2.py new file mode 100644 index 0000000..f1d31da --- /dev/null +++ b/timer_app2.py @@ -0,0 +1,326 @@ +import tkinter as tk +from tkinter import filedialog, messagebox, ttk +import threading +import socket +import time +import binascii + +def hexspace(data, n): + return " ".join([data[i:i + n] for i in range(0, len(data), n)]) + +def send_data(key, value): + print(f"Sending {key}: {value}") + + +class DataReceiver: + def __init__(self): + self.running = False + self.file_mode = False + self.file_path = None + + def start_tcp(self, host, port, callback): + self.running = True + def run(): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind((host, port)) + s.listen(1) + conn, addr = s.accept() + with conn: + while self.running: + data = conn.recv(1024) + if data: + callback(data.decode('utf-8')) + threading.Thread(target=run, daemon=True).start() + + def start_file(self, callback): + self.running = True + def run(): + if not self.file_path: + return + with open(self.file_path, 'r') as f: + while self.running: + line = f.readline() + if line: + callback(line.strip()) + else: + time.sleep(0.5) + threading.Thread(target=run, daemon=True).start() + + def stop(self): + self.running = False + +class DataSender: + def __init__(self): + self.targets = [] + + def add_target(self, host, port): + self.targets.append((host, port)) + + + # def send(self, data): + # for host, port in self.targets: + # try: + # with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + # s.connect((host, port)) + # s.sendall(data.encode('utf-8')) + # except Exception as e: + # print(f"Error sending data to {host}:{port}: {e}") + +class DataProcessor: + def process_protocol_a(self, data): + return data.upper() + + def process_protocol_b(self, data): + return data[::-1] + + def process_protocol_saratov(self, data): + if data == "\xff": + return + + cdata = binascii.hexlify(data.encode("utf-8")) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + temp = edata.split("FF 52") + results = [] + for i in temp: + try: + minutes = int(i.split()[5], 16) + seconds = int(i.split()[6], 16) + timer_str = f"{minutes}:{seconds:02d}" if seconds < 60 else f"{minutes}.{seconds-128}" + + seconds_24 = int(i.split()[7], 16) + timer_attack = "" + timer_pic = "D:\\Graphics\\Basketball\\24Sec_Orange.png" + if seconds_24 != 255: + if seconds_24 > 127: + seconds_24 -= 128 + timer_attack = f"{seconds_24//10}.{seconds_24%10}" + timer_pic = "D:\\Graphics\\Basketball\\24Sec_Red.png" + else: + timer_attack = seconds_24 + + quarter = int(i.split()[14][1], 16) + timeout1 = int(i.split()[10], 16) + timeout2 = int(i.split()[11], 16) + score1 = int(i.split()[8], 16) + score2 = int(i.split()[9], 16) + foul1 = int(i.split()[12], 16) + foul2 = int(i.split()[13], 16) + + data = { + "TIMER.Text": timer_str, + "ATTACK.Text": timer_attack, + "Score_Home.Text": score1, + "Score_Away.Text": score2, + "fouls1.Source": f"D:\\Graphics\\Basketball\\Home_{foul1}.png", + "fouls2.Source": f"D:\\Graphics\\Basketball\\Away_{foul2}.png", + "24SECBACKGROUND.Source": timer_pic, + } + for key, value in data.items(): + send_data(key, value) + + results.append(data) + except (IndexError, ValueError): + continue + + return results + + +class App: + def __init__(self, root): + self.receiver = DataReceiver() + self.sender = DataSender() + self.processor = DataProcessor() + + self.protocol_var = tk.StringVar(value="Protocol A") + self.mode_var = tk.StringVar(value="Log File") + + self.create_ui(root) + + def display_data(self, data): + protocol = self.protocol_var.get() + if protocol == "Protocol A": + processed_data = self.processor.process_protocol_a(data) + elif protocol == "Protocol B": + processed_data = self.processor.process_protocol_b(data) + elif protocol == "Saratov": + processed_data = self.processor.process_protocol_saratov(data) + else: + processed_data = data + + if processed_data: + self.update_send_status(True) + self.sender.send(str(processed_data)) + self.update_send_status(False) + + def create_ui(self, root): + root.title("Data Processing Application") + + self.notebook = tk.ttk.Notebook(root) + self.notebook.pack(fill="both", expand=True) + + self.settings_frame = tk.Frame(self.notebook) + self.game_frame = tk.Frame(self.notebook) + + self.notebook.add(self.settings_frame, text="Settings") + self.notebook.add(self.game_frame, text="Game") + + self.create_settings_ui(self.settings_frame) + self.create_game_ui(self.game_frame) + + def create_settings_ui(self, frame): + # Frame for receiving data + frame_receive = tk.LabelFrame(frame, text="Receive Data") + frame_receive.pack(fill="x", padx=5, pady=5) + + tk.Label(frame_receive, text="Select Mode:").pack(side="left", padx=5, pady=5) + tk.OptionMenu(frame_receive, self.mode_var, "Log File", "TCP Connection", command=self.update_mode).pack(side="left", padx=5, pady=5) + + self.file_button = tk.Button(frame_receive, text="Select Log File", command=self.select_file) + + self.tcp_frame = tk.Frame(frame_receive) + tk.Label(self.tcp_frame, text="IP:").pack(side="left") + self.tcp_ip_entry = tk.Entry(self.tcp_frame) + self.tcp_ip_entry.pack(side="left", padx=5) + tk.Label(self.tcp_frame, text="Port:").pack(side="left") + self.tcp_port_entry = tk.Entry(self.tcp_frame) + self.tcp_port_entry.pack(side="left", padx=5) + + self.start_button = tk.Button(frame_receive, text="Start", command=self.start_receiving) + self.start_button.pack(side="left", padx=5, pady=5) + tk.Button(frame_receive, text="Stop", command=self.stop_receiving).pack(side="left", padx=5, pady=5) + + # Frame for processing data + frame_process = tk.LabelFrame(frame, text="Process Data") + frame_process.pack(fill="x", padx=5, pady=5) + + tk.Label(frame_process, text="Select Protocol:").pack(side="left", padx=5, pady=5) + tk.OptionMenu(frame_process, self.protocol_var, "Protocol A", "Protocol B", "Saratov").pack(side="left", padx=5, pady=5) + + # Frame for sending data + frame_send = tk.LabelFrame(frame, text="Send Data") + frame_send.pack(fill="x", padx=5, pady=5) + + self.target_count_var = tk.IntVar(value=1) + tk.Label(frame_send, text="Number of Targets:").pack(side="left", padx=5, pady=5) + tk.Spinbox(frame_send, from_=1, to=10, textvariable=self.target_count_var, command=self.update_targets).pack(side="left", padx=5, pady=5) + + self.targets_frame = tk.Frame(frame_send) + self.targets_frame.pack(fill="x", padx=5, pady=5) + self.target_entries = [] + self.update_targets() + + tk.Button(frame_send, text="Send Data", command=self.send_data).pack(side="left", padx=5, pady=5) + + self.update_mode(self.mode_var.get()) + + def create_game_ui(self, frame): + frame_status = tk.LabelFrame(frame, text="Status") + frame_status.pack(fill="x", padx=5, pady=5) + + self.data_receive_status = tk.Label(frame_status, text="Receiving Data: Not Active", fg="red") + self.data_receive_status.pack(pady=5) + + self.data_send_status = tk.Label(frame_status, text="Sending Data: Not Active", fg="red") + self.data_send_status.pack(pady=5) + + def update_mode(self, mode): + if mode == "Log File": + self.file_button.pack(side="left", padx=5, pady=5) + self.tcp_frame.pack_forget() + self.start_button.config(state="normal") + else: + self.file_button.pack_forget() + self.tcp_frame.pack(side="left", padx=5, pady=5) + self.start_button.config(state="normal") + + def select_file(self): + self.receiver.file_path = filedialog.askopenfilename() + + def start_receiving(self): + self.start_button.config(state="disabled") + mode = self.mode_var.get() + if mode == "Log File": + if self.receiver.file_path: + self.receiver.start_file(self.display_data) + self.update_receive_status(True) + else: + messagebox.showerror("Error", "No file selected.") + elif mode == "TCP Connection": + host = self.tcp_ip_entry.get() + port = self.tcp_port_entry.get() + if host and port.isdigit(): + self.receiver.start_tcp(host, int(port), self.display_data) + self.update_receive_status(True) + else: + messagebox.showerror("Error", "Invalid IP or port.") + self.start_button.config(state="normal") + + def stop_receiving(self): + self.receiver.stop() + self.start_button.config(state="normal") + self.update_receive_status(False) + + def display_data(self, data): + protocol = self.protocol_var.get() + if protocol == "Protocol A": + processed_data = self.processor.process_protocol_a(data) + else: + processed_data = self.processor.process_protocol_b(data) + + self.update_send_status(True) + self.sender.send(processed_data) + self.update_send_status(False) + + def update_receive_status(self, active): + if active: + self.data_receive_status.config(text="Receiving Data: Active", fg="green") + else: + self.data_receive_status.config(text="Receiving Data: Not Active", fg="red") + + def update_send_status(self, active): + if active: + self.data_send_status.config(text="Sending Data: Active", fg="green") + else: + self.data_send_status.config(text="Sending Data: Not Active", fg="red") + + def update_targets(self): + for widget in self.targets_frame.winfo_children(): + widget.destroy() + + self.target_entries = [] + for i in range(self.target_count_var.get()): + target_frame = tk.Frame(self.targets_frame) + target_frame.pack(fill="x", pady=2) + + tk.Label(target_frame, text=f"Target {i+1} Host:").pack(side="left") + host_entry = tk.Entry(target_frame) + host_entry.pack(side="left", padx=5) + + tk.Label(target_frame, text="Port:").pack(side="left") + port_entry = tk.Entry(target_frame) + port_entry.pack(side="left", padx=5) + + self.target_entries.append((host_entry, port_entry)) + + def send_data(self): + data = "Sample data to send" + if not data: + messagebox.showerror("No Data", "No data to send.") + return + + self.sender.targets = [] + for host_entry, port_entry in self.target_entries: + host = host_entry.get() + port = port_entry.get() + if host and port.isdigit(): + self.sender.add_target(host, int(port)) + + self.update_send_status(True) + self.sender.send(data) + self.update_send_status(False) + +if __name__ == "__main__": + root = tk.Tk() + app = App(root) + root.mainloop() diff --git a/timer_app2_temp.py b/timer_app2_temp.py new file mode 100644 index 0000000..842ae14 --- /dev/null +++ b/timer_app2_temp.py @@ -0,0 +1,369 @@ +import tkinter as tk +from tkinter import filedialog, messagebox, ttk +import threading +import socket +import time +import binascii +import requests +import json # To handle structured data better + +def hexspace(data, n): + return " ".join([data[i:i + n] for i in range(0, len(data), n)]) + +session = requests.Session() +session.headers.update({"Connection": "keep-alive"}) + +class DataReceiver: + def __init__(self): + self.running = False + self.file_mode = False + self.file_path = None + self.manual_mode = False + + def start_tcp(self, host, port, callback): + self.running = True + def run(): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind((host, port)) + s.listen(1) + conn, addr = s.accept() + with conn: + while self.running: + data = conn.recv(1024) + if data: + callback(data.decode('utf-8')) + threading.Thread(target=run, daemon=True).start() + + def start_file(self, callback, timeout): + self.running = True + def run(): + if not self.file_path: + return + with open(self.file_path, 'r') as f: + while self.running: + if self.manual_mode: + continue + line = f.readline() + if line: + try: + # Safely parse the data, assuming the data format is correct + callback(json.loads(line.strip().split(" DEBUG ")[1])) + except Exception as e: + print(f"Error parsing line: {e}") + time.sleep(timeout) + threading.Thread(target=run, daemon=True).start() + + def read_next_line(self, callback): + if not self.file_path: + return + with open(self.file_path, 'r') as f: + line = f.readline() + if line: + try: + callback(json.loads(line.strip().split(" DEBUG ")[1])) + except Exception as e: + print(f"Error parsing line: {e}") + + def stop(self): + self.running = False + +class DataSender: + def __init__(self): + self.targets = [] + + def add_target(self, host, port): + self.targets.append((host, port)) + + def send(self, data): + for host, port in self.targets: + try: + url = f"http://{host}:{port}/API/" + for k, v in data.items(): + par = "SetText" if k.split(".")[1] == "Text" else "SetImage" + params = { + "Function": par, + "Input": 23, + "SelectedName": k, + "Value": v, + } + session.get(url, params=params) + except Exception as e: + print(f"Error sending data to {host}:{port}: {e}") + +class DataProcessor: + def process_protocol_a(self, data): + return data.upper() + + def process_protocol_b(self, data): + return data[::-1] + + def process_protocol_saratov(self, data): + if data == "\xff": + return None + + cdata = binascii.hexlify(data.encode()) # Ensure data is properly encoded to bytes + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + temp = edata.split("FF 52") + processed_data = [] + for i in temp: + try: + parts = i.split() + minutes = int(parts[5], 16) + seconds = int(parts[6], 16) + timer_str = f"{minutes}:{seconds:02d}" if seconds < 60 else f"{minutes}.{seconds - 128}" + + seconds_24 = int(parts[7], 16) + timer_attack = "" + timer_pic = "D:/Графика/БАСКЕТБОЛ/ЕДИНАЯ ЛИГА ВТБ 2022-2023/Scorebug Indicators/24Sec_Orange.png" + if seconds_24 != 255: + if seconds_24 > 127: + seconds_24 -= 128 + timer_attack = f"{seconds_24 // 10}.{seconds_24 % 10}" + timer_pic = "D:/Графика/БАСКЕТБОЛ/ЕДИНАЯ ЛИГА ВТБ 2022-2023/Scorebug Indicators/24Sec_Red.png" + else: + timer_attack = seconds_24 + + quarter = int(parts[14][1], 16) + timeout1 = int(parts[10], 16) + timeout2 = int(parts[11], 16) + score1 = int(parts[8], 16) + score2 = int(parts[9], 16) + foul1 = int(parts[12], 16) + foul2 = int(parts[13], 16) + + data_dict = { + "TIMER.Text": timer_str, + "ATTACK.Text": timer_attack, + "Score_Home.Text": score1, + "Score_Away.Text": score2, + "fouls1.Source": f"D:/Графика/БАСКЕТБОЛ/ЕДИНАЯ ЛИГА ВТБ 2022-2023/Scorebug Indicators/Home_{foul1}.png", + "fouls2.Source": f"D:/Графика/БАСКЕТБОЛ/ЕДИНАЯ ЛИГА ВТБ 2022-2023/Scorebug Indicators/Away_{foul2}.png", + "24SECBACKGROUND.Source": timer_pic, + } + + processed_data.append(data_dict) + except (IndexError, ValueError) as e: + print(f"Error processing data: {e}") + continue + + return processed_data + +class App: + def __init__(self, root): + self.receiver = DataReceiver() + self.sender = DataSender() + self.processor = DataProcessor() + + self.protocol_var = tk.StringVar(value="Protocol A") + self.mode_var = tk.StringVar(value="Log File") + self.read_mode_var = tk.StringVar(value="Automatic") + self.timeout_var = tk.DoubleVar(value=0.5) + + self.create_ui(root) + + def display_data(self, data): + protocol = self.protocol_var.get() + if protocol == "Protocol A": + processed_data = self.processor.process_protocol_a(data) + elif protocol == "Protocol B": + processed_data = self.processor.process_protocol_b(data) + elif protocol == "Saratov": + processed_data = self.processor.process_protocol_saratov(data) + else: + processed_data = data + + if processed_data: + self.update_send_status(True) + self.sender.send(processed_data) + self.update_send_status(False) + + self.log_text.insert(tk.END, f"{data}\n") + self.log_text.see(tk.END) + + self.processed_data_text.insert(tk.END, f"{processed_data}\n") + self.processed_data_text.see(tk.END) + + def create_ui(self, root): + root.title("Data Processing Application") + + self.notebook = ttk.Notebook(root) + self.notebook.pack(fill="both", expand=True) + + self.settings_frame = tk.Frame(self.notebook) + self.game_frame = tk.Frame(self.notebook) + + self.notebook.add(self.settings_frame, text="Settings") + self.notebook.add(self.game_frame, text="Game") + + self.create_settings_ui(self.settings_frame) + self.create_game_ui(self.game_frame) + + def create_settings_ui(self, frame): + frame_receive = tk.LabelFrame(frame, text="Receive Data") + frame_receive.pack(fill="x", padx=5, pady=5) + + tk.Label(frame_receive, text="Select Mode:").pack(side="left", padx=5, pady=5) + tk.OptionMenu(frame_receive, self.mode_var, "Log File", "TCP Connection", command=self.update_mode).pack(side="left", padx=5, pady=5) + + self.file_button = tk.Button(frame_receive, text="Select Log File", command=self.select_file) + + self.tcp_frame = tk.Frame(frame_receive) + tk.Label(self.tcp_frame, text="IP:").pack(side="left") + self.tcp_ip_entry = tk.Entry(self.tcp_frame) + self.tcp_ip_entry.pack(side="left", padx=5) + self.tcp_ip_entry.insert(0, "192.168.127.254") # Example default IP address + tk.Label(self.tcp_frame, text="Port:").pack(side="left") + self.tcp_port_entry = tk.Entry(self.tcp_frame) + self.tcp_port_entry.pack(side="left", padx=5) + self.tcp_port_entry.insert(0, 1993) # Example default port + + self.read_mode_frame = tk.Frame(frame_receive) + tk.Label(self.read_mode_frame, text="Read Mode:").pack(side="left", padx=5, pady=5) + tk.OptionMenu(self.read_mode_frame, self.read_mode_var, "Automatic", "Manual", command=self.update_read_mode).pack(side="left", padx=5, pady=5) + tk.Label(self.read_mode_frame, text="Timeout (s):").pack(side="left", padx=5, pady=5) + self.timeout_entry = tk.Entry(self.read_mode_frame, textvariable=self.timeout_var) + self.timeout_entry.pack(side="left", padx=5) + self.manual_read_button = tk.Button(self.read_mode_frame, text="Read Next Line", command=self.read_next_line) + + self.start_button = tk.Button(frame_receive, text="Start", command=self.start_receiving) + self.start_button.pack(side="left", padx=5, pady=5) + tk.Button(frame_receive, text="Stop", command=self.stop_receiving).pack(side="left", padx=5, pady=5) + + frame_process = tk.LabelFrame(frame, text="Process Data") + frame_process.pack(fill="x", padx=5, pady=5) + + tk.Label(frame_process, text="Select Protocol:").pack(side="left", padx=5, pady=5) + tk.OptionMenu(frame_process, self.protocol_var, "Protocol A", "Protocol B", "Saratov").pack(side="left", padx=5, pady=5) + + frame_send = tk.LabelFrame(frame, text="Send Data") + frame_send.pack(fill="x", padx=5, pady=5) + + self.target_count_var = tk.IntVar(value=1) + tk.Label(frame_send, text="Number of Targets:").pack(side="left", padx=5, pady=5) + tk.Spinbox(frame_send, from_=1, to=10, textvariable=self.target_count_var, command=self.update_targets).pack(side="left", padx=5, pady=5) + + self.targets_frame = tk.Frame(frame_send) + self.targets_frame.pack(fill="x", padx=5, pady=5) + self.target_entries = [] + self.update_targets() + + tk.Button(frame_send, text="Send Data", command=self.send_data).pack(side="left", padx=5, pady=5) + + self.update_mode(self.mode_var.get()) + + def create_game_ui(self, frame): + frame_status = tk.LabelFrame(frame, text="Status") + frame_status.pack(fill="x", padx=5, pady=5) + + self.data_receive_status = tk.Label(frame_status, text="Receiving Data: Not Active", fg="red") + self.data_receive_status.pack(pady=5) + + self.data_send_status = tk.Label(frame_status, text="Sending Data: Not Active", fg="red") + self.data_send_status.pack(pady=5) + + frame_log = tk.LabelFrame(frame, text="Log") + frame_log.pack(fill="both", expand=True, padx=5, pady=5) + + self.log_text = tk.Text(frame_log, height=10, state="normal") + self.log_text.pack(fill="both", expand=True, padx=5, pady=5) + + frame_processed = tk.LabelFrame(frame, text="Processed Data") + frame_processed.pack(fill="both", expand=True, padx=5, pady=5) + + self.processed_data_text = tk.Text(frame_processed, height=10, state="normal") + self.processed_data_text.pack(fill="both", expand=True, padx=5, pady=5) + + def update_mode(self, mode): + if mode == "Log File": + self.file_button.pack(side="left", padx=5, pady=5) + self.tcp_frame.pack_forget() + self.read_mode_frame.pack(fill="x", padx=5, pady=5) + self.start_button.config(state="normal") + else: + self.file_button.pack_forget() + self.read_mode_frame.pack_forget() + self.tcp_frame.pack(side="left", padx=5, pady=5) + self.start_button.config(state="normal") + + def update_read_mode(self, mode): + if mode == "Automatic": + self.timeout_entry.config(state="normal") + self.manual_read_button.pack_forget() + self.receiver.manual_mode = False + else: + self.timeout_entry.config(state="disabled") + self.manual_read_button.pack(side="left", padx=5, pady=5) + self.receiver.manual_mode = True + + def select_file(self): + self.receiver.file_path = filedialog.askopenfilename() + + def start_receiving(self): + self.start_button.config(state="disabled") + mode = self.mode_var.get() + if mode == "Log File": + if self.receiver.file_path: + timeout = self.timeout_var.get() if self.read_mode_var.get() == "Automatic" else 0 + self.receiver.start_file(self.display_data, timeout) + self.update_receive_status(True) + else: + messagebox.showerror("Error", "No file selected.") + elif mode == "TCP Connection": + host = self.tcp_ip_entry.get() + port = self.tcp_port_entry.get() + if host and port.isdigit(): + self.receiver.start_tcp(host, int(port), self.display_data) + self.update_receive_status(True) + else: + messagebox.showerror("Error", "Invalid IP or port.") + self.start_button.config(state="normal") + + def stop_receiving(self): + self.receiver.stop() + self.start_button.config(state="normal") + self.update_receive_status(False) + + def read_next_line(self): + self.receiver.read_next_line(self.display_data) + + def update_receive_status(self, active): + if active: + self.data_receive_status.config(text="Receiving Data: Active", fg="green") + else: + self.data_receive_status.config(text="Receiving Data: Not Active", fg="red") + + def update_send_status(self, active): + if active: + self.data_send_status.config(text="Sending Data: Active", fg="green") + else: + self.data_send_status.config(text="Sending Data: Not Active", fg="red") + + def update_targets(self): + for widget in self.targets_frame.winfo_children(): + widget.destroy() + + self.target_entries = [] + for i in range(self.target_count_var.get()): + target_frame = tk.Frame(self.targets_frame) + target_frame.pack(fill="x", pady=2) + + tk.Label(target_frame, text=f"Target {i+1}:").pack(side="left", padx=5, pady=5) + host_entry = tk.Entry(target_frame) + host_entry.pack(side="left", padx=5) + host_entry.insert(0, f"192.168.1.{i+1}") + self.target_entries.append(host_entry) + + def send_data(self): + if not self.target_entries: + messagebox.showerror("Error", "No targets defined.") + return + + targets = [(entry.get(), 8080) for entry in self.target_entries] + self.sender.targets = targets + self.sender.send({"data": "sample"}) + +if __name__ == "__main__": + root = tk.Tk() + app = App(root) + root.mainloop() diff --git a/timer_app3.py b/timer_app3.py new file mode 100644 index 0000000..161111c --- /dev/null +++ b/timer_app3.py @@ -0,0 +1,415 @@ +import tkinter as tk +from tkinter import filedialog, messagebox, ttk +import threading +import socket +import time +import binascii +import requests +from concurrent.futures import ThreadPoolExecutor + +def hexspace(data, n): + return " ".join([data[i:i + n] for i in range(0, len(data), n)]) + +session = requests.Session() +session.headers.update({"Connection": "keep-alive"}) + +class DataReceiver: + def __init__(self): + self.running = False + self.file_mode = False + self.file_path = None + self.manual_mode = False + + def start_tcp(self, host, port, callback): + self.running = True + def run(): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.bind((host, port)) + s.listen(1) + conn, addr = s.accept() + with conn: + while self.running: + data = conn.recv(1024) + if data: + callback(data.decode('utf-8')) + threading.Thread(target=run, daemon=True).start() + + def start_file(self, callback, timeout): + self.running = True + def run(): + if not self.file_path: + return + with open(self.file_path, 'r') as f: + while self.running: + if self.manual_mode: + continue + line = f.readline() + if line: + callback(eval(line.strip().split(" DEBUG ")[1])) + time.sleep(timeout) + threading.Thread(target=run, daemon=True).start() + + def read_next_line(self, callback): + if not self.file_path: + return + with open(self.file_path, 'r') as f: + line = f.readline() + if line: + callback(eval(line.strip().split(" DEBUG ")[1])) + + def stop(self): + self.running = False + +class DataSender: + def __init__(self): + self.targets = [] + self.session = requests.Session() + self.session.headers.update({"Connection": "keep-alive"}) + + def add_target(self, host, port): + self.targets.append((host, port)) + + + def send(self, data): + """Многопоточная отправка данных на все указанные цели.""" + if not self.targets: + print("No targets available to send data.") + return + + def send_to_target(target): + host, port = target + url = f"http://{host}:{port}/API/" + try: + for k, v in data.items(): + par = "SetText" if k.split(".")[1] == "Text" else "SetImage" + params = { + "Function": par, + "Input": 51, + "SelectedName": k, + "Value": v, + } + response = self.session.get(url, params=params, timeout=5) + response.raise_for_status() # Проверяет, есть ли ошибки HTTP + except requests.exceptions.RequestException as e: + print(f"Error sending data to {host}:{port}: {e}") + + # Используем ThreadPoolExecutor для многопоточной отправки + with ThreadPoolExecutor(max_workers=5) as executor: # max_workers можно настроить + executor.map(send_to_target, self.targets) + + + # def send(self, data): + # for host, port in self.targets: + # try: + # url = f"http://{host}:{port}/API/" + # print(data) + # for k,v in data.items(): + # par = "SetText" if k.split(".")[1] == "Text" else "SetImage" + # params = { + # "Function": par, + # "Input": 51, + # "SelectedName": k, + # "Value": v, + # } + # session.get(url, params=params) + # except Exception as e: + # print(f"Error sending data to {host}:{port}: {e}") + + # def send(self, data): + # for host, port in self.targets: + # try: + # with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + # s.connect((host, port)) + # s.sendall(data.encode('utf-8')) + # except Exception as e: + # print(f"Error sending data to {host}:{port}: {e}") + +class DataProcessor: + def process_protocol_a(self, data): + return data.upper() + + def process_protocol_b(self, data): + return data[::-1] + + def process_protocol_saratov(self, data): + if data == "\xff": + return + + cdata = binascii.hexlify(data) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + temp = edata.split("FF 52") + # results = [] + for i in temp: + try: + minutes = int(i.split()[5], 16) + seconds = int(i.split()[6], 16) + timer_str = f"{minutes}:{seconds:02d}" if seconds < 60 else f"{minutes}.{seconds-128}" + + seconds_24 = int(i.split()[7], 16) + timer_attack = "" + timer_pic = "D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\\24Sec_Orange.png" + if seconds_24 != 255: + if seconds_24 > 127: + seconds_24 -= 128 + timer_attack = f"{seconds_24//10}.{seconds_24%10}" + timer_pic = "D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\\24Sec_Red.png" + else: + timer_attack = seconds_24 + + quarter = int(i.split()[14][1], 16) + timeout1 = int(i.split()[10], 16) + timeout2 = int(i.split()[11], 16) + score1 = int(i.split()[8], 16) + score2 = int(i.split()[9], 16) + foul1 = int(i.split()[12], 16) + foul2 = int(i.split()[13], 16) + + data = { + "TIMER.Text": timer_str, + "ATTACK.Text": timer_attack, + "Score_Home.Text": score1, + "Score_Away.Text": score2, + "fouls1.Source": f"D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\Home_{foul1}.png", + "fouls2.Source": f"D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\Away_{foul2}.png", + "24SECBACKGROUND.Source": timer_pic, + } + + # results.append(data) + except (IndexError, ValueError): + continue + + return data + +class App: + def __init__(self, root): + self.receiver = DataReceiver() + self.sender = DataSender() + self.processor = DataProcessor() + + self.protocol_var = tk.StringVar(value="Protocol A") + self.mode_var = tk.StringVar(value="Log File") + self.read_mode_var = tk.StringVar(value="Automatic") + self.timeout_var = tk.DoubleVar(value=0.5) + + self.create_ui(root) + + def display_data(self, data): + protocol = self.protocol_var.get() + if protocol == "Protocol A": + processed_data = self.processor.process_protocol_a(data) + elif protocol == "Protocol B": + processed_data = self.processor.process_protocol_b(data) + elif protocol == "Saratov": + processed_data = self.processor.process_protocol_saratov(data) + else: + processed_data = data + + if processed_data: + self.update_send_status(True) + self.sender.send(processed_data) + self.update_send_status(False) + + self.log_text.insert(tk.END, f"{data}\n") + self.log_text.see(tk.END) + + self.processed_data_text.insert(tk.END, f"{processed_data}\n") + self.processed_data_text.see(tk.END) + + def create_ui(self, root): + root.title("Data Processing Application") + + self.notebook = ttk.Notebook(root) + self.notebook.pack(fill="both", expand=True) + + self.settings_frame = tk.Frame(self.notebook) + self.game_frame = tk.Frame(self.notebook) + + self.notebook.add(self.settings_frame, text="Settings") + self.notebook.add(self.game_frame, text="Game") + + self.create_settings_ui(self.settings_frame) + self.create_game_ui(self.game_frame) + + def create_settings_ui(self, frame): + frame_receive = tk.LabelFrame(frame, text="Receive Data") + frame_receive.pack(fill="x", padx=5, pady=5) + + tk.Label(frame_receive, text="Select Mode:").pack(side="left", padx=5, pady=5) + tk.OptionMenu(frame_receive, self.mode_var, "Log File", "TCP Connection", command=self.update_mode).pack(side="left", padx=5, pady=5) + + self.file_button = tk.Button(frame_receive, text="Select Log File", command=self.select_file) + + self.tcp_frame = tk.Frame(frame_receive) + tk.Label(self.tcp_frame, text="IP:").pack(side="left") + self.tcp_ip_entry = tk.Entry(self.tcp_frame) + self.tcp_ip_entry.pack(side="left", padx=5) + self.tcp_ip_entry.insert(0, "192.168.127.254") # например, default IP адрес + tk.Label(self.tcp_frame, text="Port:").pack(side="left") + self.tcp_port_entry = tk.Entry(self.tcp_frame) + self.tcp_port_entry.pack(side="left", padx=5) + self.tcp_port_entry.insert(0, 1993) # например, default порт + + self.read_mode_frame = tk.Frame(frame_receive) + tk.Label(self.read_mode_frame, text="Read Mode:").pack(side="left", padx=5, pady=5) + tk.OptionMenu(self.read_mode_frame, self.read_mode_var, "Automatic", "Manual", command=self.update_read_mode).pack(side="left", padx=5, pady=5) + tk.Label(self.read_mode_frame, text="Timeout (s):").pack(side="left", padx=5, pady=5) + self.timeout_entry = tk.Entry(self.read_mode_frame, textvariable=self.timeout_var) + self.timeout_entry.pack(side="left", padx=5) + self.manual_read_button = tk.Button(self.read_mode_frame, text="Read Next Line", command=self.read_next_line) + + self.start_button = tk.Button(frame_receive, text="Start", command=self.start_receiving) + self.start_button.pack(side="left", padx=5, pady=5) + tk.Button(frame_receive, text="Stop", command=self.stop_receiving).pack(side="left", padx=5, pady=5) + + frame_process = tk.LabelFrame(frame, text="Process Data") + frame_process.pack(fill="x", padx=5, pady=5) + + tk.Label(frame_process, text="Select Protocol:").pack(side="left", padx=5, pady=5) + tk.OptionMenu(frame_process, self.protocol_var, "Protocol A", "Protocol B", "Saratov").pack(side="left", padx=5, pady=5) + + frame_send = tk.LabelFrame(frame, text="Send Data") + frame_send.pack(fill="x", padx=5, pady=5) + + self.target_count_var = tk.IntVar(value=1) + tk.Label(frame_send, text="Number of Targets:").pack(side="left", padx=5, pady=5) + tk.Spinbox(frame_send, from_=1, to=10, textvariable=self.target_count_var, command=self.update_targets).pack(side="left", padx=5, pady=5) + + self.targets_frame = tk.Frame(frame_send) + self.targets_frame.pack(fill="x", padx=5, pady=5) + self.target_entries = [] + self.update_targets() + + tk.Button(frame_send, text="Send Data", command=self.send_data).pack(side="left", padx=5, pady=5) + + self.update_mode(self.mode_var.get()) + + def create_game_ui(self, frame): + frame_status = tk.LabelFrame(frame, text="Status") + frame_status.pack(fill="x", padx=5, pady=5) + + self.data_receive_status = tk.Label(frame_status, text="Receiving Data: Not Active", fg="red") + self.data_receive_status.pack(pady=5) + + self.data_send_status = tk.Label(frame_status, text="Sending Data: Not Active", fg="red") + self.data_send_status.pack(pady=5) + + frame_log = tk.LabelFrame(frame, text="Log") + frame_log.pack(fill="both", expand=True, padx=5, pady=5) + + self.log_text = tk.Text(frame_log, height=10, state="normal") + self.log_text.pack(fill="both", expand=True, padx=5, pady=5) + + frame_processed = tk.LabelFrame(frame, text="Processed Data") + frame_processed.pack(fill="both", expand=True, padx=5, pady=5) + + self.processed_data_text = tk.Text(frame_processed, height=10, state="normal") + self.processed_data_text.pack(fill="both", expand=True, padx=5, pady=5) + + def update_mode(self, mode): + if mode == "Log File": + self.file_button.pack(side="left", padx=5, pady=5) + self.tcp_frame.pack_forget() + self.read_mode_frame.pack(fill="x", padx=5, pady=5) + self.start_button.config(state="normal") + else: + self.file_button.pack_forget() + self.read_mode_frame.pack_forget() + self.tcp_frame.pack(side="left", padx=5, pady=5) + self.start_button.config(state="normal") + + def update_read_mode(self, mode): + if mode == "Automatic": + self.timeout_entry.config(state="normal") + self.manual_read_button.pack_forget() + self.receiver.manual_mode = False + else: + self.timeout_entry.config(state="disabled") + self.manual_read_button.pack(side="left", padx=5, pady=5) + self.receiver.manual_mode = True + + def select_file(self): + self.receiver.file_path = filedialog.askopenfilename() + + def start_receiving(self): + self.start_button.config(state="disabled") + mode = self.mode_var.get() + if mode == "Log File": + if self.receiver.file_path: + timeout = self.timeout_var.get() if self.read_mode_var.get() == "Automatic" else 0 + self.receiver.start_file(self.display_data, timeout) + self.update_receive_status(True) + else: + messagebox.showerror("Error", "No file selected.") + elif mode == "TCP Connection": + host = self.tcp_ip_entry.get() + port = self.tcp_port_entry.get() + if host and port.isdigit(): + self.receiver.start_tcp(host, int(port), self.display_data) + self.update_receive_status(True) + else: + messagebox.showerror("Error", "Invalid IP or port.") + self.start_button.config(state="normal") + + def stop_receiving(self): + self.receiver.stop() + self.start_button.config(state="normal") + self.update_receive_status(False) + + def read_next_line(self): + self.receiver.read_next_line(self.display_data) + + def update_receive_status(self, active): + if active: + self.data_receive_status.config(text="Receiving Data: Active", fg="green") + else: + self.data_receive_status.config(text="Receiving Data: Not Active", fg="red") + + def update_send_status(self, active): + if active: + self.data_send_status.config(text="Sending Data: Active", fg="green") + else: + self.data_send_status.config(text="Sending Data: Not Active", fg="red") + + def update_targets(self): + for widget in self.targets_frame.winfo_children(): + widget.destroy() + + self.target_entries = [] + for i in range(self.target_count_var.get()): + target_frame = tk.Frame(self.targets_frame) + target_frame.pack(fill="x", pady=2) + + tk.Label(target_frame, text=f"Target {i+1} Host:").pack(side="left") + host_entry = tk.Entry(target_frame) + host_entry.pack(side="left", padx=5) + host_entry.insert(0, "127.0.0.1") + + tk.Label(target_frame, text="Port:").pack(side="left") + port_entry = tk.Entry(target_frame) + port_entry.pack(side="left", padx=5) + port_entry.insert(0, 8088) + + self.target_entries.append((host_entry, port_entry)) + + def send_data(self): + data = "Sample data to send" + if not data: + messagebox.showerror("No Data", "No data to send.") + return + + self.sender.targets = [] + for host_entry, port_entry in self.target_entries: + host = host_entry.get() + port = port_entry.get() + if host and port.isdigit(): + self.sender.add_target(host, int(port)) + + self.update_send_status(True) + self.sender.send(data) + self.update_send_status(False) + +if __name__ == "__main__": + root = tk.Tk() + app = App(root) + root.mainloop() diff --git a/timer_app4.py b/timer_app4.py new file mode 100644 index 0000000..046ca46 --- /dev/null +++ b/timer_app4.py @@ -0,0 +1,620 @@ +import tkinter as tk +from tkinter import filedialog, messagebox, ttk +import threading +import socket +import time +import binascii +import requests +from concurrent.futures import ThreadPoolExecutor + + +def hexspace(data, n): + return " ".join([data[i : i + n] for i in range(0, len(data), n)]) + + +class DataReceiver: + def __init__(self): + self.running = False + self.file_mode = False + self.file_path = None + self.manual_mode = False + + def start_tcp(self, host, port, callback): + self.running = True + + def run(): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + try: + # Подключаемся к серверу + s.connect((host, port)) + + # Отправляем строку "hello" в виде байтов + s.sendall("hello".encode("utf-8")) + + # Основной цикл для получения данных + while self.running: + try: + # Получаем данные от сервера (максимум 1024 байта) + data = s.recv(1024) + + if data: + try: + # Преобразуем байты в строку UTF-8 + decoded_data = data + # Вызываем callback с декодированными данными + callback(decoded_data) + except UnicodeDecodeError: + print(f"Ошибка декодирования данных: {data}") + callback(data.decode("latin1", errors="replace")) + else: + # Если data пустое, соединение закрылось + print("Сервер закрыл соединение.") + break + except (socket.error, OSError) as e: + print(f"Ошибка приёма данных: {e}") + break + except Exception as e: + print(f"Ошибка подключения: {e}") + finally: + print("Соединение закрыто.") + self.running = False + + threading.Thread(target=run, daemon=True).start() + + def start_file(self, callback, timeout): + self.running = True + + def run(): + if not self.file_path: + return + with open(self.file_path, "r") as f: + while self.running: + if self.manual_mode: + continue + line = f.readline() + if line: + callback(eval(line.strip().split(" DEBUG ")[1])) + time.sleep(timeout) + + threading.Thread(target=run, daemon=True).start() + + def read_next_line(self, callback): + if not self.file_path: + return + with open(self.file_path, "r") as f: + line = f.readline() + if line: + callback(eval(line.strip().split(" DEBUG ")[1])) + + def stop(self): + self.running = False + + +class DataSender: + def __init__(self): + self.targets = [] + self.session = requests.Session() + self.session.headers.update({"Connection": "keep-alive"}) + + def add_target(self, host, port): + self.targets.append((host, port)) + + def send(self, data): + """Многопоточная отправка данных на все указанные цели.""" + if not self.targets: + print("No targets available to send data.") + return + + def send_to_target(target): + host, port = target + url = f"http://{host}:{port}/API/" + # url = f"http://{host}:{port}/" + try: + for k, v in data.items(): + par = "SetText" if k.split(".")[1] == "Text" else "SetImage" + params = { + "Function": par, + "Input": 51, + "SelectedName": k, + "Value": v, + } + + # params = { + # "action": "set_text", + # "layer": f"SCORE STRIPE FLAGS INTRO\Data\{k}", + # "value": str(v), + # "channel": "live1", + # } + + # params = { + # "action": "set_data_source_query_parameter", + # "data_source": "timer_data", + # "parameter": k, + # "value": v, + # } + # params = { "action" : "set_data_source_query_parameter", "data_source" : "XML/JSON Source 11", "parameter" : "TIMER", "value" : "London" } + # print(url, params) + response = self.session.get(url, params=params, timeout=5) + # response = self.session.post(url, params=params) + # print(response.headers) + response.raise_for_status() # Проверяет, есть ли ошибки HTTP + except requests.exceptions.RequestException as e: + print(f"Error sending data to {host}:{port}: {e}") + + # Используем ThreadPoolExecutor для многопоточной отправки + with ThreadPoolExecutor( + max_workers=5 + ) as executor: # max_workers можно настроить + executor.map(send_to_target, self.targets) + + def check_vmix_connections(self): + """Проверяем соединения для всех целей и обновляем индикаторы.""" + for index, (host_entry, port_entry) in enumerate(self.target_entries): + host = host_entry.get() + port = port_entry.get() + + if not port.isdigit(): + continue # Пропускаем некорректные порты + + connected = self.sender.check_vmix_connection(host, int(port)) + self.update_connection_indicator(index, connected) + + def update_connection_indicator(self, index, connected): + """Обновляем цвет индикатора для определенной цели.""" + color = "green" if connected else "red" + self.connection_indicators[index].itemconfig("indicator", fill=color) + + def check_vmix_connection(self, host, port): + url = f"http://{host}:{port}/API/" + # url = f"http://{host}:{port}" + try: + response = self.session.get(url, timeout=2) # Таймаут в секундах + return response.status_code == 200 + except requests.exceptions.RequestException: + return False + + +class DataProcessor: + def process_protocol_a(self, data): + return data.upper() + + def process_protocol_b(self, data): + return data[::-1] + + def process_chine(self, data): + cdata = binascii.hexlify(data) + ddata = cdata.decode("utf-8", errors="replace").upper() + edata = hexspace(ddata, 2) + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + # print(temp_new) + timer = f"{temp_new[3]}:{temp_new[2]}" + seconds = temp_new[5] + milliseconds = str(temp_new[4])[0] + if int(seconds) > 4: + temp = float(f"{seconds}.{milliseconds}") + if int(milliseconds) >= 5: + seconds = int(seconds) + 1 + else: + seconds = seconds + timer_attack = seconds + timer_color = "#59358A" + else: + timer_attack = f"{seconds}.{milliseconds}" + timer_color = "#FF6A13" + if temp_new[0] in [16, 24]: + timer_attack = "" + timer_color = "#000000" + data = { + "12sec.Text": timer_attack, + "12SecBackground.Fill.Color": timer_color, + } + return data + + def process_protocol_saratov(self, data): + if data == "\xff": + return + + cdata = binascii.hexlify(data) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + temp = edata.split("FF 52") + for i in temp: + try: + minutes = int(i.split()[5], 16) + seconds = int(i.split()[6], 16) + timer_str = ( + f"{minutes}:{seconds:02d}" + if seconds < 60 + else f"{minutes}.{seconds-128}" + ) + + seconds_24 = int(i.split()[7], 16) + timer_attack = "" + timer_pic = "D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\\24Sec_Orange.png" + if seconds_24 != 255: + if seconds_24 > 127: + seconds_24 -= 128 + timer_attack = f"{seconds_24//10}.{seconds_24%10}" + timer_pic = "D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\\24Sec_Red.png" + else: + timer_attack = seconds_24 + + quarter = int(i.split()[14][1], 16) + timeout1 = int(i.split()[10], 16) + timeout2 = int(i.split()[11], 16) + score1 = int(i.split()[8], 16) + score2 = int(i.split()[9], 16) + foul1 = int(i.split()[12], 16) + foul2 = int(i.split()[13], 16) + + data = { + "TIMER.Text": timer_str, + "ATTACK.Text": timer_attack, + "Score_Home.Text": score1, + "Score_Away.Text": score2, + "fouls1.Source": f"D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\Home_{foul1}.png", + "fouls2.Source": f"D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\Away_{foul2}.png", + "24SECBACKGROUND.Source": timer_pic, + } + # data = { + # "Timer": timer_str, + # # "Attack": timer_attack, + # # "Score1": score1, + # # "Score2": score2, + # # "fouls1.Source": f"D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\Home_{foul1}.png", + # # "fouls2.Source": f"D:\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\Away_{foul2}.png", + # # "24SECBACKGROUND.Source": timer_pic, + # } + + except (IndexError, ValueError): + continue + + return data + + +class App: + def __init__(self, root): + self.receiver = DataReceiver() + self.sender = DataSender() + self.processor = DataProcessor() + + self.protocol_var = tk.StringVar(value="Protocol A") + self.mode_var = tk.StringVar(value="Log File") + self.read_mode_var = tk.StringVar(value="Automatic") + self.timeout_var = tk.DoubleVar(value=0.5) + + self.create_ui(root) + self.start_vmix_connection_check() + + def display_data(self, data): + protocol = self.protocol_var.get() + if protocol == "Protocol A": + processed_data = self.processor.process_protocol_a(data) + elif protocol == "Protocol B": + processed_data = self.processor.process_protocol_b(data) + elif protocol == "Saratov": + processed_data = self.processor.process_protocol_saratov(data) + elif protocol == "Chine": + processed_data = self.processor.process_chine(data) + else: + processed_data = data + + if processed_data: + self.update_send_status(True) + self.sender.send(processed_data) + self.update_send_status(False) + + self.log_text.insert(tk.END, f"{data}\n") + self.log_text.see(tk.END) + + self.processed_data_text.insert(tk.END, f"{processed_data}\n") + self.processed_data_text.see(tk.END) + + def create_ui(self, root): + root.title("Data Processing Application") + + self.notebook = ttk.Notebook(root) + self.notebook.pack(fill="both", expand=True) + + self.settings_frame = tk.Frame(self.notebook) + self.game_frame = tk.Frame(self.notebook) + + self.notebook.add(self.settings_frame, text="Settings") + self.notebook.add(self.game_frame, text="Game") + + self.create_settings_ui(self.settings_frame) + self.create_game_ui(self.game_frame) + + def create_settings_ui(self, frame): + frame_receive = tk.LabelFrame(frame, text="Receive Data") + frame_receive.pack(fill="x", padx=5, pady=5) + + tk.Label(frame_receive, text="Select Mode:").pack(side="left", padx=5, pady=5) + tk.OptionMenu( + frame_receive, + self.mode_var, + "Log File", + "TCP Connection", + command=self.update_mode, + ).pack(side="left", padx=5, pady=5) + + self.file_button = tk.Button( + frame_receive, text="Select Log File", command=self.select_file + ) + + self.tcp_frame = tk.Frame(frame_receive) + tk.Label(self.tcp_frame, text="IP:").pack(side="left") + self.tcp_ip_entry = tk.Entry(self.tcp_frame) + self.tcp_ip_entry.pack(side="left", padx=5) + self.tcp_ip_entry.insert(0, "192.168.127.254") # например, default IP адрес + tk.Label(self.tcp_frame, text="Port:").pack(side="left") + self.tcp_port_entry = tk.Entry(self.tcp_frame) + self.tcp_port_entry.pack(side="left", padx=5) + self.tcp_port_entry.insert(0, 1993) # например, default порт + + self.read_mode_frame = tk.Frame(frame_receive) + tk.Label(self.read_mode_frame, text="Read Mode:").pack( + side="left", padx=5, pady=5 + ) + tk.OptionMenu( + self.read_mode_frame, + self.read_mode_var, + "Automatic", + "Manual", + command=self.update_read_mode, + ).pack(side="left", padx=5, pady=5) + tk.Label(self.read_mode_frame, text="Timeout (s):").pack( + side="left", padx=5, pady=5 + ) + self.timeout_entry = tk.Entry( + self.read_mode_frame, textvariable=self.timeout_var + ) + self.timeout_entry.pack(side="left", padx=5) + self.manual_read_button = tk.Button( + self.read_mode_frame, text="Read Next Line", command=self.read_next_line + ) + + self.start_button = tk.Button( + frame_receive, text="Start", command=self.start_receiving + ) + self.start_button.pack(side="left", padx=5, pady=5) + tk.Button(frame_receive, text="Stop", command=self.stop_receiving).pack( + side="left", padx=5, pady=5 + ) + + frame_process = tk.LabelFrame(frame, text="Process Data") + frame_process.pack(fill="x", padx=5, pady=5) + + tk.Label(frame_process, text="Select Protocol:").pack( + side="left", padx=5, pady=5 + ) + tk.OptionMenu( + frame_process, + self.protocol_var, + "Protocol A", + "Protocol B", + "Saratov", + "Chine", + ).pack(side="left", padx=5, pady=5) + + frame_send = tk.LabelFrame(frame, text="Send Data") + frame_send.pack(fill="x", padx=5, pady=5) + + self.target_count_var = tk.IntVar(value=1) + tk.Label(frame_send, text="Number of Targets:").pack( + side="left", padx=5, pady=5 + ) + tk.Spinbox( + frame_send, + from_=1, + to=10, + textvariable=self.target_count_var, + command=self.update_targets, + ).pack(side="left", padx=5, pady=5) + + self.targets_frame = tk.Frame(frame_send) + self.targets_frame.pack(fill="x", padx=5, pady=5) + self.target_entries = [] + self.update_targets() + + tk.Button(frame_send, text="Send Data", command=self.send_data).pack( + side="left", padx=5, pady=5 + ) + + self.update_mode(self.mode_var.get()) + + def create_game_ui(self, frame): + frame_status = tk.LabelFrame(frame, text="Status") + frame_status.pack(fill="x", padx=5, pady=5) + + # Canvas indicators + self.receive_status_canvas = tk.Canvas(frame_status, width=20, height=20) + self.receive_status_canvas.create_oval( + 2, 2, 18, 18, fill="red", tags="indicator" + ) + self.receive_status_canvas.pack(side="left", padx=10, pady=5) + tk.Label(frame_status, text="Receiving Data").pack(side="left") + + self.send_status_canvas = tk.Canvas(frame_status, width=20, height=20) + self.send_status_canvas.create_oval(2, 2, 18, 18, fill="red", tags="indicator") + self.send_status_canvas.pack(side="left", padx=10, pady=5) + tk.Label(frame_status, text="Sending Data").pack(side="left") + + frame_log = tk.LabelFrame(frame, text="Log") + frame_log.pack(fill="both", expand=True, padx=5, pady=5) + + self.log_text = tk.Text(frame_log, height=10, state="normal") + self.log_text.pack(fill="both", expand=True, padx=5, pady=5) + + frame_processed = tk.LabelFrame(frame, text="Processed Data") + frame_processed.pack(fill="both", expand=True, padx=5, pady=5) + + self.processed_data_text = tk.Text(frame_processed, height=10, state="normal") + self.processed_data_text.pack(fill="both", expand=True, padx=5, pady=5) + + # self.vmix_status_indicator = tk.Canvas(frame_status, width=20, height=20) + # self.vmix_status_indicator.pack(side="left", padx=5, pady=5) + # self.update_vmix_indicator(False) + + # tk.Label(frame_status, text="vMix Connection").pack(side="left", padx=5, pady=5) + + # def update_vmix_indicator(self, connected): + # self.vmix_status_indicator.delete("all") + # color = "green" if connected else "red" + # self.vmix_status_indicator.create_oval(2, 2, 18, 18, fill=color) + + # def check_vmix_connection(self): + # if not self.target_entries: + # return False + + # host_entry, port_entry = self.target_entries[0] # Проверяем первую цель + # host = host_entry.get() + # port = port_entry.get() + # if not port.isdigit(): + # return False + + # connected = self.sender.check_vmix_connection(host, int(port)) + # self.update_vmix_indicator(connected) + # return connected + + def check_vmix_connections(self): + for index, (host_entry, port_entry) in enumerate(self.target_entries): + host = host_entry.get() + port = port_entry.get() + + if not port.isdigit(): + continue # Пропускаем некорректные порты + + connected = self.sender.check_vmix_connection(host, int(port)) + self.update_connection_indicator(index, connected) + + def update_connection_indicator(self, index, connected): + color = "green" if connected else "red" + self.connection_indicators[index].itemconfig("indicator", fill=color) + + def start_vmix_connection_check(self): + """Периодически проверяем соединения.""" + + def check_loop(): + while True: + self.check_vmix_connections() + time.sleep(1) + + threading.Thread(target=check_loop, daemon=True).start() + + def update_mode(self, mode): + if mode == "Log File": + self.file_button.pack(side="left", padx=5, pady=5) + self.tcp_frame.pack_forget() + self.read_mode_frame.pack(fill="x", padx=5, pady=5) + self.start_button.config(state="normal") + else: + self.file_button.pack_forget() + self.read_mode_frame.pack_forget() + self.tcp_frame.pack(side="left", padx=5, pady=5) + self.start_button.config(state="normal") + + def update_read_mode(self, mode): + if mode == "Automatic": + self.timeout_entry.config(state="normal") + self.manual_read_button.pack_forget() + self.receiver.manual_mode = False + else: + self.timeout_entry.config(state="disabled") + self.manual_read_button.pack(side="left", padx=5, pady=5) + self.receiver.manual_mode = True + + def select_file(self): + self.receiver.file_path = filedialog.askopenfilename() + + def start_receiving(self): + self.start_button.config(state="disabled") + mode = self.mode_var.get() + if mode == "Log File": + if self.receiver.file_path: + timeout = ( + self.timeout_var.get() + if self.read_mode_var.get() == "Automatic" + else 0 + ) + self.receiver.start_file(self.display_data, timeout) + self.update_receive_status(True) + else: + messagebox.showerror("Error", "No file selected.") + elif mode == "TCP Connection": + host = self.tcp_ip_entry.get() + port = self.tcp_port_entry.get() + if host and port.isdigit(): + self.receiver.start_tcp(host, int(port), self.display_data) + self.update_receive_status(True) + else: + messagebox.showerror("Error", "Invalid IP or port.") + self.start_button.config(state="normal") + + def stop_receiving(self): + self.receiver.stop() + self.start_button.config(state="normal") + self.update_receive_status(False) + + def read_next_line(self): + self.receiver.read_next_line(self.display_data) + + def update_receive_status(self, active): + color = "green" if active else "red" + self.receive_status_canvas.itemconfig("indicator", fill=color) + + def update_send_status(self, active): + color = "green" if active else "red" + self.send_status_canvas.itemconfig("indicator", fill=color) + + def update_targets(self): + for widget in self.targets_frame.winfo_children(): + widget.destroy() + + self.target_entries = [] + self.connection_indicators = [] # Храним индикаторы состояния + + for i in range(self.target_count_var.get()): + target_frame = tk.Frame(self.targets_frame) + target_frame.pack(fill="x", pady=2) + + tk.Label(target_frame, text=f"Target {i+1} Host:").pack(side="left") + host_entry = tk.Entry(target_frame) + host_entry.pack(side="left", padx=5) + host_entry.insert(0, "127.0.0.1") + + tk.Label(target_frame, text="Port:").pack(side="left") + port_entry = tk.Entry(target_frame) + port_entry.pack(side="left", padx=5) + port_entry.insert(0, 8088) + + indicator = tk.Canvas(target_frame, width=20, height=20) + indicator.create_oval(2, 2, 18, 18, fill="red", tags="indicator") + indicator.pack(side="left", padx=5) + + self.target_entries.append((host_entry, port_entry)) + self.connection_indicators.append(indicator) + + def send_data(self): + data = "Sample data to send" + if not data: + messagebox.showerror("No Data", "No data to send.") + return + + self.sender.targets = [] + for host_entry, port_entry in self.target_entries: + host = host_entry.get() + port = port_entry.get() + if host and port.isdigit(): + self.sender.add_target(host, int(port)) + + # self.update_send_status(True) + self.sender.send(data) + # self.update_send_status(False) + + +if __name__ == "__main__": + root = tk.Tk() + app = App(root) + root.mainloop() diff --git a/timer_china_tcp.py b/timer_china_tcp.py new file mode 100644 index 0000000..67611dd --- /dev/null +++ b/timer_china_tcp.py @@ -0,0 +1,155 @@ +import sys +from socket import * +from datetime import datetime +import logging +import os +import time +import binascii +import requests + + +HOST = "192.168.127.254" +PORT = 1993 +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + + +def hexspace(string, length): + return " ".join(string[i : i + length] for i in range(0, len(string), length)) + + +def parse(line): + cdata = binascii.hexlify(line) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + + if len(edata.split()) == 33: + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + minutes = temp_new[6] + seconds = temp_new[7] + milliseconds = temp_new[8] + timer_str = ( + f"{minutes}:{seconds:02d}" + if minutes != 0 + else f"{seconds:02d}.{milliseconds}" + ) + active_temp = temp_new[ + 9 + ] # 133 - таймер идёт | 132 - таймер стоит | 128 - не игровое время стоит | 129 - не игровое время идёт + + if temp_new[-2] != 0: + time_attack = ( + temp_new[-4] if temp_new[-4] > 4 else f"{temp_new[-4]}.{temp_new[-3]}" + ) + else: + time_attack = "" # temp_new[-2] == 1 - таймер идёт | 2 - таймер стоит | 0 - таймер не отображён + + # print(f"{str(temp_new):<120}__{timer_str:<7}__{time_attack:<3}__") + else: + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + + # time.sleep(0.1) + + +def read_logs(): + with open("timer_NN_2023-12-20_18-17-29.log", "r") as file: + # with open("timer_NN_test.log", "r") as file: + temp_line = "" + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = eval(parts[1]) + parse(data) + time.sllep(0.1) + + # if len(eval(data)) > 30 and eval(data)[-7] == "00": + # time.sleep(.1) + # else: + # time.sleep(1) + + +def main(): + current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_Chine_tcp_{current_time}.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + logging.debug(data) + cdata = binascii.hexlify(data) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + timer = f"{temp_new[3]}:{temp_new[2]}" + seconds = temp_new[5] + milliseconds = str(temp_new[4])[0] + if int(seconds) > 4: + temp = float(f"{seconds}.{milliseconds}") + if int(milliseconds) >= 5: + seconds = int(seconds) + 1 + else: + seconds = seconds + timer_attack = seconds + timer_color = "#FF6EAB" + else: + timer_attack = f"{seconds}.{milliseconds}" + timer_color = "#561D93" + if temp_new[0] in [16, 24]: + timer_attack = "" + timer_color = "#000000" + url = "http://127.0.0.1:8088/API/" + params = { + "Function": "SetText", + "Input": 151, + "SelectedName": "12sec.Text", + "Value": timer_attack, + } + params1 = { + "Function": "SetColor", + "Input": 150, + "SelectedName": "12SecBackground.Fill.Color", + "Value": timer_color, + } + requests.get(url, params=params) + requests.get(url, params=params1) + print( + f"data: {edata}", + temp_new, + timer, + f"{seconds}.{milliseconds}, attack: {timer_attack}", + ) + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + except Exception: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + # read_logs() + except KeyboardInterrupt: + sys.exit(1) + except Exception as ex: + print(ex) diff --git a/timer_chine.py b/timer_chine.py new file mode 100644 index 0000000..12e1c32 --- /dev/null +++ b/timer_chine.py @@ -0,0 +1,119 @@ +import serial +from serial import SerialException +import datetime +import binascii +import logging +import time +import json + +import re + +# Configuration Data (later to be put in Panel2Net.conf) +# SerialPort: Name of RPi serial port receiving the panel data +# SerialPort = "COM1" +SerialPort = "COM1" +# BaudRate: Serial port speed (Baud, Default will be adjusted later) +BaudRate = 19200 +# PackageByTime: Time Duration until a package is closed +# and sent off (seconds) +PackageByTime = 0.1 +# PackageByLength* Length (in bytes) of data input +# until a package is closed and sent off +PackageByLength = 128 +# PackageByLength = 256 #попробовать нужно !!!!!!!!!!!!!!!!!!!! +# PackageByLength = 256 + +# MaxBuffer before flushing (in order to avoid buffer overflow) +BufferMax = 2000 + + +# LogFileName: Name of LogFile +current_time = datetime.datetime.now().strftime("%Y-%m-%d_%H-%M-%S") +LogFileName = f"timer_megasport5_{current_time}.log" +# LogFileSize Maximum Size of LogFile (in Mbytes) +LogFileSize = 10 +# LogLevel Minimum Severity Level to be logged (see severity in Logs) +LogLevel = "E" + +logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", +) + +def hexspace(string, length): + return ' '.join(string[i:i+length] for i in range(0,len(string),length)) + +ser = serial.Serial() +ser.port = SerialPort +ser.baudrate = BaudRate +ser.bytesize = serial.EIGHTBITS # number of bits per bytes +ser.parity = serial.PARITY_NONE # PARITY_NONE # set parity check: no parity +ser.stopbits = serial.STOPBITS_ONE # number of stop bits +ser.timeout = PackageByTime # non-block read +ser.xonxoff = False # disable software flow control +ser.rtscts = False # disable hardware (RTS/CTS) flow control +ser.dsrdtr = False # disable hardware (DSR/DTR) flow control +ser.writeTimeout = 0 # timeout for write + +while True: + try: + print("Initializing") + ser.close() + ser.open() + if ser.is_open: + try: + ser.reset_input_buffer() + # flush input buffer, discarding all its contents + ser.reset_output_buffer() + # flush output buffer, aborting current output + # and discard all that is in buffer + RequestCount = 0 + print("Port Opening") + # Initialise RetryCounter + RetryCount = 0 + # Initialise Variable to take remainder string + remainder_hex = b"" + + while True: + # Read from Serial Interface + response = ser.read(PackageByLength) + # print(response) + if len(response) > 0: + # In case there is something coming down the serial path + logging.debug(response) + + if response != b"": + cdata = binascii.hexlify(response) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + timer = f"{temp_new[3]}:{temp_new[2]}" + seconds = temp_new[5] + # milliseconds = str(temp_new[6])[0] + print(len(temp_new), edata, temp_new, timer, seconds) + + + else: + # In case nothing is coming down the serial interface + print( + "\rWaiting for serial input...", + end=" ", + flush=True, + ) + + # in case that the Serial Read or HTTP request fails + except Exception as e1: + print("error communicating...: " + str(e1)) + logging.error("error communicating...: " + str(e1)) + + else: + print("Port Opening Failed... trying again in 5 seconds") + time.sleep(0.1) + ser.close() + + except SerialException: + print("No port connected... trying again in 5 seconds") + time.sleep(0.1) diff --git a/timer_chine_tcp.py b/timer_chine_tcp.py new file mode 100644 index 0000000..669caaf --- /dev/null +++ b/timer_chine_tcp.py @@ -0,0 +1,165 @@ +import sys +from socket import * +from datetime import datetime +import logging +import os +import time +import binascii +import requests + + +HOST = "192.168.127.254" +PORT = 1993 +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + + +def hexspace(string, length): + return " ".join(string[i : i + length] for i in range(0, len(string), length)) + + +def parse(line): + cdata = binascii.hexlify(line) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + + if len(edata.split()) == 33: + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + minutes = temp_new[6] + seconds = temp_new[7] + milliseconds = temp_new[8] + timer_str = ( + f"{minutes}:{seconds:02d}" + if minutes != 0 + else f"{seconds:02d}.{milliseconds}" + ) + active_temp = temp_new[ + 9 + ] # 133 - таймер идёт | 132 - таймер стоит | 128 - не игровое время стоит | 129 - не игровое время идёт + + if temp_new[-2] != 0: + time_attack = ( + temp_new[-4] if temp_new[-4] > 4 else f"{temp_new[-4]}.{temp_new[-3]}" + ) + else: + time_attack = "" # temp_new[-2] == 1 - таймер идёт | 2 - таймер стоит | 0 - таймер не отображён + + # print(f"{str(temp_new):<120}__{timer_str:<7}__{time_attack:<3}__") + else: + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + + # time.sleep(0.1) + + +def read_logs(): + with open("timer_NN_2023-12-20_18-17-29.log", "r") as file: + # with open("timer_NN_test.log", "r") as file: + temp_line = "" + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = eval(parts[1]) + parse(data) + time.sllep(0.1) + + # if len(eval(data)) > 30 and eval(data)[-7] == "00": + # time.sleep(.1) + # else: + # time.sleep(1) + + +def main(): + current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_Chine_tcp_{current_time}.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + # new_data = { + # "timeGFX": "0:00", + # "time_attackGFX": "", + # "quarter": "0", + # "points1": "0", + # "points2": "0", + # "foul1": "0", + # "foul2": "0", + # "foul_pic1": "", + # "foul_pic2": "", + # "time_attac_pic": "", + # } + # with open(PATH, "w", encoding="utf-8") as file: + # json.dump([new_data], file, ensure_ascii=False, indent=4) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + logging.debug(data) + cdata = binascii.hexlify(data) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + temp_data = edata.split() + temp_new = [int(t, 16) for t in temp_data] + # print(temp_new) + timer = f"{temp_new[3]}:{temp_new[2]}" + seconds = temp_new[5] + milliseconds = str(temp_new[4])[0] + if int(seconds) > 4: + temp = float(f"{seconds}.{milliseconds}") + if int(milliseconds) >= 5: + seconds = int(seconds) + 1 + else: + seconds = seconds + timer_attack = seconds + timer_color = "#59358A" + else: + timer_attack = f"{seconds}.{milliseconds}" + timer_color = "#FF6A13" + if temp_new[0] in [16, 24]: + timer_attack = "" + timer_color = "#000000" + url = "http://127.0.0.1:8088/API/" + params = { + "Function": "SetText", + "Input": 221, + "SelectedName": "12sec.Text", + "Value": timer_attack, + } + params1 = { + "Function": "SetColor", + "Input": 221, + "SelectedName": "12SecBackground.Fill.Color", + "Value": timer_color, + } + requests.get(url, params=params) + requests.get(url, params=params1) + print( + f"data: {edata}", + temp_new, + timer, + f"{seconds}.{milliseconds}, attack: {timer_attack}", + ) + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + # read_logs() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_exe.py b/timer_exe.py new file mode 100644 index 0000000..16c4d73 --- /dev/null +++ b/timer_exe.py @@ -0,0 +1,169 @@ +import tkinter as tk +from tkinter import filedialog, ttk, messagebox +import threading +import serial +import socket +import json +import os +import time +from data_sender import send_data_to_ips + + +class ConnectionApp: + def __init__(self, root): + self.root = root + self.root.title("Connection and Parser Application") + + # Variables + self.connection_type = tk.StringVar(value="IP") + self.log_file_path = tk.StringVar(value="No file selected") + self.parser_type = tk.StringVar(value="Parser 1") + self.ip_address = tk.StringVar(value="127.0.0.1") + self.port = tk.IntVar(value=8080) + self.com_port = tk.StringVar(value="COM1") + self.baud_rate = tk.IntVar(value=9600) + self.data = "" + self.http_destinations = [] + + # Thread control + self.connection_thread = None + self.is_running = False + + # UI + self.create_widgets() + + def create_widgets(self): + # Connection Type Selection + tk.Label(self.root, text="Connection Type:").grid(row=0, column=0, pady=5, sticky="e") + connection_menu = ttk.Combobox( + self.root, textvariable=self.connection_type, values=["IP", "Log File", "COM"], state="readonly" + ) + connection_menu.grid(row=0, column=1, pady=5, sticky="w") + + # IP Settings + tk.Label(self.root, text="IP Address:").grid(row=1, column=0, pady=5, sticky="e") + tk.Entry(self.root, textvariable=self.ip_address).grid(row=1, column=1, pady=5, sticky="w") + + tk.Label(self.root, text="Port:").grid(row=2, column=0, pady=5, sticky="e") + tk.Entry(self.root, textvariable=self.port).grid(row=2, column=1, pady=5, sticky="w") + + # Log File Selection + tk.Label(self.root, text="Log File:").grid(row=3, column=0, pady=5, sticky="e") + tk.Button(self.root, text="Select File", command=self.select_log_file).grid(row=3, column=1, pady=5, sticky="w") + tk.Label(self.root, textvariable=self.log_file_path).grid(row=4, column=0, columnspan=2, sticky="w") + + # COM Port Settings + tk.Label(self.root, text="COM Port:").grid(row=5, column=0, pady=5, sticky="e") + tk.Entry(self.root, textvariable=self.com_port).grid(row=5, column=1, pady=5, sticky="w") + + tk.Label(self.root, text="Baud Rate:").grid(row=6, column=0, pady=5, sticky="e") + tk.Entry(self.root, textvariable=self.baud_rate).grid(row=6, column=1, pady=5, sticky="w") + + # Parser Selection + tk.Label(self.root, text="Parser:").grid(row=7, column=0, pady=5, sticky="e") + parser_menu = ttk.Combobox( + self.root, textvariable=self.parser_type, values=["Parser 1", "Parser 2", "Parser 3"], state="readonly" + ) + parser_menu.grid(row=7, column=1, pady=5, sticky="w") + + # Control Buttons + tk.Button(self.root, text="Start", command=self.start_connection).grid(row=8, column=0, pady=10) + tk.Button(self.root, text="Stop", command=self.stop_connection).grid(row=8, column=1, pady=10) + + # Destination Management + tk.Button(self.root, text="Add HTTP Destination", command=self.add_http_destination).grid(row=9, column=0, pady=10) + tk.Button(self.root, text="Show Destinations", command=self.show_destinations).grid(row=9, column=1, pady=10) + + def select_log_file(self): + file_path = filedialog.askopenfilename( + title="Select Log File", filetypes=[("Log files", "*.log"), ("All files", "*.*")] + ) + if file_path: + self.log_file_path.set(file_path) + + def start_connection(self): + if self.connection_thread and self.connection_thread.is_alive(): + messagebox.showinfo("Info", "Connection is already running.") + return + + self.is_running = True + connection_type = self.connection_type.get() + + if connection_type == "IP": + self.connection_thread = threading.Thread(target=self.connect_via_ip, daemon=True) + elif connection_type == "Log File": + self.connection_thread = threading.Thread(target=self.read_log_file, daemon=True) + elif connection_type == "COM": + self.connection_thread = threading.Thread(target=self.connect_via_com, daemon=True) + else: + messagebox.showerror("Error", "Unknown connection type.") + return + + self.connection_thread.start() + + def stop_connection(self): + self.is_running = False + if self.connection_thread and self.connection_thread.is_alive(): + self.connection_thread.join() + messagebox.showinfo("Info", "Connection stopped.") + + def connect_via_ip(self): + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.connect((self.ip_address.get(), self.port.get())) + while self.is_running: + data = s.recv(1024).decode() + self.process_data(data) + except Exception as e: + messagebox.showerror("Error", f"IP connection error: {e}") + + def read_log_file(self): + try: + with open(self.log_file_path.get(), "r") as file: + while self.is_running: + line = file.readline() + if not line: + time.sleep(0.1) + continue + self.process_data(line) + except Exception as e: + messagebox.showerror("Error", f"Log file error: {e}") + + def connect_via_com(self): + try: + with serial.Serial(self.com_port.get(), self.baud_rate.get(), timeout=1) as ser: + while self.is_running: + data = ser.readline().decode() + self.process_data(data) + except Exception as e: + messagebox.showerror("Error", f"COM port error: {e}") + + def process_data(self, data): + parser = self.get_parser(self.parser_type.get()) + parsed_data = parser(data) + self.data = parsed_data + send_data_to_ips(parsed_data, self.http_destinations) + + def get_parser(self, parser_name): + if parser_name == "Parser 1": + return lambda x: {"parsed": f"Parser 1 processed {x}"} + elif parser_name == "Parser 2": + return lambda x: {"parsed": f"Parser 2 processed {x}"} + elif parser_name == "Parser 3": + return lambda x: {"parsed": f"Parser 3 processed {x}"} + else: + return lambda x: {"error": "No valid parser selected"} + + def add_http_destination(self): + ip = tk.simpledialog.askstring("Add HTTP Destination", "Enter IP (http://:port):") + if ip: + self.http_destinations.append(ip) + + def show_destinations(self): + messagebox.showinfo("HTTP Destinations", "\n".join(self.http_destinations)) + + +if __name__ == "__main__": + root = tk.Tk() + app = ConnectionApp(root) + root.mainloop() diff --git a/timer_hockey_balashikha.py b/timer_hockey_balashikha.py new file mode 100644 index 0000000..05bc766 --- /dev/null +++ b/timer_hockey_balashikha.py @@ -0,0 +1,107 @@ +import socket +from datetime import datetime +import json + +HOST = "10.1.68.38" # local +PORT = 40001 +PATH = "D:\\timer.json" + + +def connect(): + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: + s.connect((HOST, PORT)) + s.sendall(b"Hello, world") + data = s.recv(1024) + return data + + +def save_log(name, data): + current_time = datetime.now().strftime("%d-%m-%Y %H:%M:%S.%f") + message_with_time = f"[{current_time}] {data}" + with open(name, "a") as file: + file.write(message_with_time + "\n") + + +def formatted_data(data): + save_log("logs_balashikha.txt", data) + + data_converted = list(data) + data_formatted = [ + str(hex_value // 16) + str(hex_value % 16) for hex_value in data_converted + ] + save_log("logs_balashikha_formatted.txt", data_formatted) + + +def parse(data_formatted): + # print(len(data_formatted)) + # print(data_formatted) + with open(PATH, "r", encoding="utf-8") as f: + new_data = json.load(f) + new_data = new_data[0] + + if len(data_formatted) > 30: + if data_formatted[17] == "010": + if data_formatted[-8] in ["01", "05"]: + timer_str = ( + f"{int(data_formatted[-7])}:{data_formatted[-6]}" + if int(data_formatted[-7]) != 0 + else f"{int(data_formatted[-6])}.{int(data_formatted[-5])}" + ) + new_data["timeGFX"] = timer_str + new_data["minutesGFX"] = int( + data_formatted[-7] + ) # [25] #data_formatted[17] = 010 - таймер data_formatted[-8] = 05 - овертайм, 06 - перерыв между основным временем и овертаймом, 01 - игровое время, 02 - перерыв между периодами + new_data["secondsGFX"] = data_formatted[-6] # [26] + else: + timer_str = f"{int(data_formatted[-7])}:{data_formatted[-6]}" + new_data["timeNotGame"] = timer_str + + if len(data_formatted) == 58: + new_data[ + "timeDel1" + ] = f"{int(data_formatted[26])}:{data_formatted[27]}" # data_formatted[17] = 24 - удаление + new_data["timeDel2"] = f"{int(data_formatted[41])}:{data_formatted[42]}" + + try: + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + print(new_data) + except Exception: + pass + + +def main(): + while True: + data = connect() + data_new = formatted_data(data) + parse(data_new) + + +def read_logs(): + import time + with open("test_logs_balashikha_new.txt", "r") as file: + for line in file: + parts = line.strip().split("] ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = parts[1] + parse(eval(data)) + if len(eval(data)) > 30 and eval(data)[-7] == "00": + time.sleep(.1) + else: + time.sleep(1) + + +if __name__ == "__main__": + new_data = { + "timeGFX": "0:00", + "minutesGFX": "0", + "secondsGFX": "0", + "timeDel1": "0:00", + "timeDel2": "0:00", + "timeNotGame": "0:00", + } + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + # main() + read_logs() diff --git a/timer_jet.py b/timer_jet.py new file mode 100644 index 0000000..07c5697 --- /dev/null +++ b/timer_jet.py @@ -0,0 +1,203 @@ +import sys +from socket import * +from datetime import datetime +import logging +import os +import time +import binascii +import requests + + +HOST = "127.0.0.1" +PORT = 50000 +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + +import socket + +sock = socket.socket() +sock.bind(('', PORT)) +sock.listen(1) +conn, addr = sock.accept() +print ('connected:', addr) + +def send_data_CW(name, value): + try: + with socket.socket(AF_INET, SOCK_STREAM) as tcp_socket: + tcp_socket.connect(('192.168.1.170', 5115)) + data = f"{name}={value}\n".encode() + # print(f"Sending: {data}") # Отладка + tcp_socket.sendall(data) + # print("Data sent!") # Подтверждение отправки + except Exception as e: + print(f"Error sending TCP data: {e}") + +def send_vmix(params): + try: + url = "http://192.168.1.240:8088/API/" + requests.get(url, params=params) + except Exception as ex: + print(ex) + +def parse(line, score1, score2): + temp = line.split('#') + diff1, diff2 = None, None + t = temp[0] + # for t in temp: + if t not in [" ", ""]: + a = t.split('/') + print(a) + timer_str = f"{a[4]}:{a[5] if len(a[5]) != 1 else f'0{a[5]}'}" if a[4] != "0" else f"{a[5]}.{a[6]}" + timer_attack_str = a[2] + points1 = a[7] + points2 = a[8] + quarter = a[13] + if score1 != points1: + diff1 = int(points1) - int(score1) + score1 = points1 + if score2 != points2: + score2 = points2 + diff2 = int(points2) - int(score2) + + fouls1 = a[9] + fouls2 = a[10] + path = r"D:\Графика\БАСКЕТБОЛ\FIBA" + if int(fouls1) > 4: + foul_pic1 = path + "\HOME-FOUL4.png" + else: + foul_pic1 = path + f"\HOME-FOUL{fouls1}.png" + if int(fouls2) > 4: + foul_pic2 = path + "\AWAY-FOUL4.png" + else: + foul_pic2 = path + f"\AWAY-FOUL{fouls2}.png" + + data = { + "TIMER": timer_str, + "ATTACK": timer_attack_str, + "Score_Home": score1, + "Score_Away": score2, + "fouls1": fouls1, + "fouls2": fouls2, + "quarter": quarter, + } + + send_data_CW("TIMER", data["TIMER"]) + send_data_CW("ATTACK", data["ATTACK"]) + send_data_CW("Score_Home", data["Score_Home"]) + send_data_CW("Score_Away", data["Score_Away"]) + send_data_CW("fouls1", data["fouls1"]) + send_data_CW("fouls2", data["fouls2"]) + send_data_CW("quarter", data["quarter"]) + + params = { + "Function": "SetText", + "Input": 2, + "SelectedName": "ATTACK.Text", + "Value": data["ATTACK"], + # "SelectedName": "TIME.Text", + # "Value": timer_str, + } + send_vmix(params) + params = { + "Function": "SetText", + "Input": 2, + "SelectedName": "TIME.Text", + "Value": data["TIMER"], + } + send_vmix(params) + params = { + "Function": "SetText", + "Input": 2, + "SelectedName": "SCORE1.Text", + "Value": data["Score_Home"], + } + send_vmix(params) + params = { + "Function": "SetText", + "Input": 2, + "SelectedName": "SCORE2.Text", + "Value": data["Score_Away"], + } + send_vmix(params) + # params = { + # "Function": "SetText", + # "Input": 20, + # "SelectedName": "SCOREDIFF1.Text", + # "Value": f"+{diff1}", + # } + # requests.get(url, params=params) + # params = { + # "Function": "SetText", + # "Input": 20, + # "SelectedName": "SCOREDIFF2.Text", + # "Value": f"+{diff2}", + # } + # requests.get(url, params=params) + + params = { + "Function": "SetImage", + "Input": 2, + "SelectedName": "FOULS_HOME.Source", + "Value": foul_pic1, + } + send_vmix(params) + params = { + "Function": "SetImage", + "Input": 2, + "SelectedName": "FOULS_AWAY.Source", + "Value": foul_pic2, + } + send_vmix(params) + print(timer_str, timer_attack_str, points1, points2,fouls1, fouls2, diff1, diff2, a) + return score1, score2 + + +score1, score2 = 0, 0 +while True: + data = conn.recv(1024) + line = data.decode("utf-8") + print(line) + if not data: + break + score1, score2 = parse(line, score1, score2) + +conn.close() + + + + + + + +# def main(): +# try: +# tcp_socket = socket(AF_INET, SOCK_STREAM) +# tcp_socket.connect((HOST, PORT)) +# data = str.encode("hello") +# tcp_socket.send(data) +# data = bytes.decode(data) +# while True: +# data = tcp_socket.recv(1024) +# print(data) +# # url = "http://127.0.0.1:8088/API/" +# # params = { +# # "Function": "SetText", +# # "Input": 221, +# # "SelectedName": "12sec.Text", +# # "Value": timer_attack, +# # } +# # params1 = { +# # "Function": "SetColor", +# # "Input": 221, +# # "SelectedName": "12SecBackground.Fill.Color", +# # "Value": timer_color, +# # } +# # requests.get(url, params=params) +# except KeyboardInterrupt: +# tcp_socket.close() +# sys.exit(1) + + +# if __name__ == "__main__": +# main() diff --git a/timer_nata_test (2).py b/timer_nata_test (2).py new file mode 100644 index 0000000..9199402 --- /dev/null +++ b/timer_nata_test (2).py @@ -0,0 +1,189 @@ +import sys +import json +from socket import * +from datetime import datetime +import logging +import os +import time +import binascii +import requests + + +HOST = "192.168.127.254" +PORT = 1993 +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + +session = requests.Session() +session.headers.update({"Connection": "keep-alive"}) + + +def hexspace(string, length): + return " ".join(string[i : i + length] for i in range(0, len(string), length)) + + +def send_data(name, value): + url = "http://127.0.0.1:8088/API/" + par = "SetText" if name.split(".")[1] == "Text" else "SetImage" + params = { + "Function": par, + "Input": 51, + "SelectedName": name, + "Value": value, + } + session.get(url, params=params) + +def parse_new(line): + try: + with open(PATH, "r", encoding="utf-8") as f: + new_data = json.load(f) + except json.decoder.JSONDecodeError: + new_data = [ + { + "timeGFX": "0:00", + "time_attackGFX": "", + "quarter": "0", + "points1": "0", + "points2": "0", + "foul1": "0", + "foul2": "0", + "foul_pic1": "", + "foul_pic2": "", + "time_attac_pic": "", + "timeout1": "0", + "timeout2": "0", + } + ] + + cdata = binascii.hexlify(line) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + temp = edata.split("FF 52") + print(line) + for i in temp: + if "7D 4A C0 0A" in i: #основной таймер + minutes = int(i.split()[-5], ) + seconds = int(i.split()[-4], ) + milliseconds = int(i.split()[-3], ) + timer_str = ( + f"{minutes}:{seconds:02d}" if minutes != 0 else f"{seconds}.{milliseconds}" + ) + send_data("TIMER.Text", timer_str) + + # print(i.split()[-7], i) + # if i.split()[-7] == "13" or i.split()[-7] == "10": + # new_data[0]["timeGFX"] = timer_str + elif "7D 4A C0 07" in i: #Счет + if i.split()[-7] == "06": #Счет первой команды + score1 = int(i.split()[-4], 16) + # new_data[0]["points1"] = score1 + send_data("Score_Home.Text", score1) + elif i.split()[-7] == "07": #Счет второй команды + score2 = int(i.split()[-4], 16) + send_data("Score_Away.Text", score2) + # new_data[0]["points2"] = score2 + else: + print("[СЧЁТ] == НЕПОНЯТНО") + elif "7D 4A C0 06" in i: #Информация + if i.split()[-6] == "09": #фолы первой команды + foul1 = int(i.split()[-3], 16) + # new_data[0]["foul1"] = foul1 + send_data("fouls1.Source", f"D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\Home_{foul1}.png") + elif i.split()[-6] == "0A": #фолы второй команды + foul2 = int(i.split()[-3], 16) + send_data("fouls2.Source", f"D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\Away_{foul2}.png") + # new_data[0]["foul2"] = foul2 + elif i.split()[-6] == "0E": #тайм-аут первой команды + time_out1 = int(i.split()[-3], 16) + # new_data[0]["timeout1"] = time_out1 + elif i.split()[-6] == "0F": #тайм-аут второй команды + time_out2 = int(i.split()[-3], 16) + # new_data[0]["timeout2"] = time_out2 + elif i.split()[-6] == "08": #четверть + quarter = int(i.split()[-3], 16) + # new_data[0]["quarter"] = quarter + + elif "79 84 C0 0A" in i: #24 секунды + # print(i) + seconds = int(i.split()[-4]) + milliseconds = int(i.split()[-3]) + if seconds < int(5): + time_attack = f"{seconds}.{milliseconds}" + timer_pic = "D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\24Sec_Red.png" + else: + time_attack = seconds + timer_pic = "D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\24Sec_Empty.png" + if time_attack == "0.0": + time_attack = "" + timer_pic = "D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\24Sec_Empty.png" + send_data("ATTACK.Text", time_attack) + send_data("24SECBACKGROUND.Source", timer_pic) + + # print(time_attack) + elif "89 4E C8 05" in i: + if i.split()[-3] == "05": #таймер 24 секунд выключен + time_attack = "" + timer_pic = "D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\24Sec_Empty.png" + send_data("ATTACK.Text", time_attack) + send_data("24SECBACKGROUND.Source", timer_pic) + # data = { + # "TIMER.Text": timer_str, + # "ATTACK.Text": time_attack, + # "Score_Home.Text": score1, + # "Score_Away.Text": score2, + # "fouls1.Source": f"D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\Home_{foul1}.png", + # "fouls2.Source": f"D:\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\Away_{foul2}.png", + # "24SECBACKGROUND.Source": timer_pic, + # } + +# def read_logs(): +# with open( +# r"C:\Users\soule\Downloads\Telegram Desktop\timer_Megasport_Nport_2024-03-05_20-00-17.log", +# "r", +# ) as file: +# for line in file: +# parts = line.strip().split(" DEBUG ") +# if len(parts) == 2: +# timestamp = parts[0][1:] +# data = eval(parts[1]) +# if b"\xf83" in data or b"\xf88" in data or b"\xf87" in data: +# parse(data) +# time.sleep(0.1) + + +def main(): + current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_Nata_Nport_{current_time}.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + logging.debug(data) + parse_new(data) + + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + # read_logs() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_playground copy.py b/timer_playground copy.py new file mode 100644 index 0000000..8f56ed6 --- /dev/null +++ b/timer_playground copy.py @@ -0,0 +1,78 @@ +import requests +import time +import json + + +URL = "http://192.168.88.247:4700/TabloData/GetTabloData" + + +def main(): + req = requests.get(URL) + new_json = { + "QUARTER": "", + "TIMER": "", + "TIMER_24": "", + "TEAM1": "", + "TEAM2": "", + "SCORE1": "", + "SCORE2": "", + "FOUL1": "", + "FOUL2": "", + } + + temp = req.json() + path_to_foul = "E:\TABLO\public_html obs — LETO 22 (09.10)" + if len(temp) > 3: + for i in temp: + if i["ID"] == "43": + new_json["TEAM1"] = i["VAL"] + elif i["ID"] == "44": + new_json["TEAM2"] = i["VAL"] + elif i["ID"] == "TIMER": + new_json["TIMER"] = i["VAL"].split(".")[0] + elif i["ID"] == "21": + new_json["SCORE1"] = i["VAL"] + elif i["ID"] == "22": + new_json["SCORE2"] = i["VAL"] + elif i["ID"] == "23": + foul1 = i["VAL"] + if int(foul1) > 5: + new_json["FOUL1"] = path_to_foul + "\\left" + "\\5.png" + else: + new_json["FOUL1"] = path_to_foul + "\\left" + f"\{i['VAL']}.png" + elif i["ID"] == "24": + foul2 = i["VAL"] + if int(foul2) > 5: + new_json["FOUL2"] = path_to_foul + "\\right" + "\\5.png" + else: + new_json["FOUL2"] = path_to_foul + "\\right" + f"\{i['VAL']}.png" + elif i["ID"] == "5": + val = "" + if i["VAL"] == "1": + val = "1ST" + elif i["VAL"] == "2": + val = "2ND" + elif i["VAL"] == "3": + val = "3RD" + elif i["VAL"] == "4": + val = "4TH" + else: + val = "OT" + str(int(i["VAL"]) - 4) + new_json["QUARTER"] = val + elif i["ID"] == "4": + new_json["TIMER_24"] = i["VAL"] + with open("E:\\TABLO\\timer_basketball.json", "w", encoding="utf-8") as file: + json.dump([new_json], file, ensure_ascii=False, indent=4) + print(new_json) + + +if __name__ == "__main__": + try: + while True: + try: + main() + time.sleep(0.1) + except Exception as ex: + print(ex) + except KeyboardInterrupt: + exit(1) diff --git a/timer_playground.py b/timer_playground.py new file mode 100644 index 0000000..d295d1b --- /dev/null +++ b/timer_playground.py @@ -0,0 +1,87 @@ +import requests +import time +import json + + +URL = "http://192.168.1.80:4700/TabloData/GetTabloData" +# URL = "http://192.168.88.247:4700/TabloData/GetTabloData" + + +def main(): + req = requests.get(URL) + new_json = { + "QUARTER": "", + "TIMER": "", + "TIMER_24": "", + "TEAM1": "", + "TEAM2": "", + "SCORE1": "", + "SCORE2": "", + "FOUL1": "", + "FOUL2": "", + } + + if req.status_code == 200: + temp = req.json() + path_to_foul = "E:\TABLO\public_html obs — LETO 22 (09.10)" + if len(temp) > 3: + for i in temp: + if i["ID"] == "43": + new_json["TEAM1"] = i["VAL"] + elif i["ID"] == "44": + new_json["TEAM2"] = i["VAL"] + elif i["ID"] == "TIMER": + new_json["TIMER"] = i["VAL"].split(".")[0] + elif i["ID"] == "21": + new_json["SCORE1"] = i["VAL"] + elif i["ID"] == "22": + new_json["SCORE2"] = i["VAL"] + elif i["ID"] == "23": + foul1 = i["VAL"] + if int(foul1) > 5: + new_json["FOUL1"] = path_to_foul + "\\left" + "\\5.png" + else: + new_json["FOUL1"] = path_to_foul + "\\left" + f"\{i['VAL']}.png" + elif i["ID"] == "24": + foul2 = i["VAL"] + if int(foul2) > 5: + new_json["FOUL2"] = path_to_foul + "\\right" + "\\5.png" + else: + new_json["FOUL2"] = ( + path_to_foul + "\\right" + f"\{i['VAL']}.png" + ) + elif i["ID"] == "5": + val = "" + if i["VAL"] == "1": + val = "1ST" + elif i["VAL"] == "2": + val = "2ND" + elif i["VAL"] == "3": + val = "3RD" + elif i["VAL"] == "4": + val = "4TH" + else: + val = "OT" + str(int(i["VAL"]) - 4) + new_json["QUARTER"] = val + elif i["ID"] == "4": + new_json["TIMER_24"] = i["VAL"] + with open( + "E:\\TABLO\\timer_basketball.json", "w", encoding="utf-8" + ) as file: + json.dump([new_json], file, ensure_ascii=False, indent=4) + print(new_json) + else: + print(f"!!!!!Error!!!!!") + + +if __name__ == "__main__": + try: + while True: + try: + main() + time.sleep(0.1) + except Exception as ex: + print(ex) + except KeyboardInterrupt: + exit(1) + diff --git a/timer_saratov.py b/timer_saratov.py new file mode 100644 index 0000000..0e96c60 --- /dev/null +++ b/timer_saratov.py @@ -0,0 +1,141 @@ +import sys +import json +from socket import * +import logging +import os +import time +import binascii +import requests + + +SETTING = "19200,None,8,1,None,Enable,RS-485(2 wire)" +HOST = "192.168.127.254" +PORT = 1993 + + +def hexspace(string, length): + return " ".join(string[i : i + length] for i in range(0, len(string), length)) + + +session = requests.Session() +session.headers.update({"Connection": "keep-alive"}) + + +def send_data(name, value): + url = "http://127.0.0.1:8088/API/" + par = "SetText" if name.split(".")[1] == "Text" else "SetImage" + params = { + "Function": par, + "Input": "SCOREBUG", + "SelectedName": name, + "Value": value, + } + session.get(url, params=params) + + +def parse_new(line): + if line == b"\xff": + return + + cdata = binascii.hexlify(line) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + temp = edata.split("FF 52") + for i in temp: + minutes = int(i.split()[5], 16) + seconds = int(i.split()[6], 16) + if seconds < 60: + timer_str = f"{minutes}:{seconds:02d}" + else: + timer_str = f"{minutes}.{seconds-128}" + seconds_24 = int(i.split()[7], 16) + timer_attack = "" + timer_pic = "D:\\YandexDisk\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\24Sec_Orange.png" + if seconds_24 == 255: + timer_attack = "" + else: + if seconds_24 > 127: + seconds_24 = seconds_24 - 128 + timer_attack = f"{seconds_24//10}.{seconds_24%10}" + timer_pic = "D:\\YandexDisk\\Графика\\БАСКЕТБОЛ\\ЕДИНАЯ ЛИГА ВТБ 2022-2023\\Scorebug Indicators\\24Sec_Red.png" + else: + timer_attack = seconds_24 + + quarter = int(i.split()[14][1], 16) + timeout1 = int(i.split()[10], 16) + timeout2 = int(i.split()[11], 16) + score1 = int(i.split()[8], 16) + score2 = int(i.split()[9], 16) + foul1 = int(i.split()[12], 16) + foul2 = int(i.split()[13], 16) + data = { + "TIMER.Text": timer_str, + "24sec.Text": timer_attack, + "SCORE1.Text": score1, + "SCORE2.Text": score2, + } + send_data("TIMER.Text", data["TIMER.Text"]) + send_data("24sec.Text", data["24sec.Text"]) + send_data("SCORE1.Text", data["SCORE1.Text"]) + send_data("SCORE2.Text", data["SCORE2.Text"]) + # send_data("fouls1.Source", data["fouls1.Source"]) + # send_data("fouls2.Source", data["fouls2.Source"]) + # send_data("24SECBACKGROUND.Source", data["24SECBACKGROUND.Source"]) + x = [int(x, 16) for x in i.split()] + print(f"{i}, timer: {timer_str}, attack: {timer_attack}, Q: {quarter}, {x}") + + +def read_logs(): + with open( + r"C:\Code\timer\LOGS\timer_SARATOV_full.log", + "r", + ) as file: + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0] + data = eval(parts[1]) + parse_new(data) + time.sleep(0.1) + + +def main(): + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_SARATOV.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + + try: + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + print(data) + logging.debug(data) + try: + parse_new(data) + except Exception as ex: + print(f"\n{ex}\n") + except Exception as ex: + pass + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + # read_logs() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_saratovCW.py b/timer_saratovCW.py new file mode 100644 index 0000000..096706c --- /dev/null +++ b/timer_saratovCW.py @@ -0,0 +1,160 @@ +import sys +import json +from socket import * +import logging +import os +import time +import binascii +import requests + + +HOST = "192.168.127.254" +PORT = 1993 + +def hexspace(string, length): + return " ".join(string[i : i + length] for i in range(0, len(string), length)) + + +session = requests.Session() +session.headers.update({"Connection": "keep-alive"}) + + +def send_data(name, value): + url = "http://127.0.0.1:8088/API/" + par = "SetText" if name.split(".")[1] == "Text" else "SetImage" + params = { + "Function": par, + "Input": 51, + "SelectedName": name, + "Value": value, + } + session.get(url, params=params) + + +def send_data_CW(name, value): + try: + with socket(AF_INET, SOCK_STREAM) as tcp_socket: + tcp_socket.connect(('localhost', 5115)) + data = f"{name}={value}\n".encode() + # print(f"Sending: {data}") # Отладка + tcp_socket.sendall(data) + # print("Data sent!") # Подтверждение отправки + except Exception as e: + print(f"Error sending TCP data: {e}") + + + + +def parse_new(line): + if line == b"\xff": + return + + cdata = binascii.hexlify(line) + ddata = cdata.decode("utf-8").upper() + edata = hexspace(ddata, 2) + temp = edata.split("FF 52") + for i in temp: + minutes = int(i.split()[5], 16) + seconds = int(i.split()[6], 16) + if seconds < 60: + timer_str = f"{minutes}:{seconds:02d}" + else: + timer_str = f"{minutes}.{seconds-128}" + seconds_24 = int(i.split()[7], 16) + timer_attack = "" + timer_pic = "D:\YandexDisk\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\\24Sec_Orange.png" + if seconds_24 == 255: + timer_attack = "" + else: + if seconds_24 > 127: + seconds_24 = seconds_24 - 128 + timer_attack = f"{seconds_24//10}.{seconds_24%10}" + timer_pic = "D:\YandexDisk\Графика\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators\\24Sec_Red.png" + else: + timer_attack = seconds_24 + + quarter = int(i.split()[14][1], 16) + timeout1 = int(i.split()[10], 16) + timeout2 = int(i.split()[11], 16) + score1 = int(i.split()[8], 16) + score2 = int(i.split()[9], 16) + foul1 = int(i.split()[12], 16) + foul2 = int(i.split()[13], 16) + data = { + "TIMER": timer_str, + "ATTACK": timer_attack, + "Score_Home": score1, + "Score_Away": score2, + "fouls1": foul1, + "fouls2": foul2, + "quarter": quarter, + } + # with open("D:\FIBA CW\\timer.json", "w", encoding="utf-8") as file: + # json.dump([data], file, ensure_ascii=False, indent=4) + send_data_CW("TIMER", data["TIMER"]) + send_data_CW("ATTACK", data["ATTACK"]) + send_data_CW("Score_Home", data["Score_Home"]) + send_data_CW("Score_Away", data["Score_Away"]) + send_data_CW("fouls1", data["fouls1"]) + send_data_CW("fouls2", data["fouls2"]) + send_data_CW("quarter", data["quarter"]) + # send_data("Score_Home", data["Score_Home"]) + # send_data("Score_Away", data["Score_Away"]) + # send_data("fouls1", data["fouls1"]) + # send_data("fouls2", data["fouls2"]) + # send_data("24SECBACKGROUND.Source", data["24SECBACKGROUND.Source"]) + # x = [int(x, 16) for x in i.split()] + print(f"{i}, {data}") + + +def read_logs(): + with open( + r"C:\Code\timer\LOGS\timer_SARATOV copy 2.log", + "r", + ) as file: + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0] + data = eval(parts[1]) + parse_new(data) + time.sleep(0.1) + + +def main(): + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_SARATOV copy.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + print(data) + logging.debug(data) + try: + parse_new(data) + except Exception as ex: + print(f"\n{ex}\n") + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + # main() + read_logs() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_stramatel copy.py b/timer_stramatel copy.py new file mode 100644 index 0000000..a995dd2 --- /dev/null +++ b/timer_stramatel copy.py @@ -0,0 +1,161 @@ +import sys +import json +from socket import * +from datetime import datetime +import logging +import os +import time + +SETTING = "19200,RS-485" +HOST = "192.168.127.254" +PORT = 1993 +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + + +def parse(line): + + # if len(line) > 6: + try: + with open(PATH, "r", encoding="utf-8") as f: + new_data = json.load(f) + timer_bool = 0 + if b"\xf87" in line: + temp_new = str(line.split(b"\xf87")[1]) + elif b"\xf88" in line: + temp_new = str(line.split(b"\xf88")[1]) + elif b"\xf83" in line: + temp_new = str(line.split(b"\xf83")[1]) + timer_bool = 1 + print(line) + timer_temp = temp_new[4:8] + # print(str(timer_temp) == '\\xf2') + if timer_temp != "\\xf2": + if timer_temp[-1] != " ": + minutes = int(timer_temp[:2]) + seconds = timer_temp[2:] + timer_str = f"{minutes}:{seconds}" + else: + seconds = int(timer_temp[0:2]) + milliseconds = int(timer_temp[2:]) + timer_str = f"{seconds}.{milliseconds}" + if timer_bool == 1: + quarter = temp_new[14] + points1 = (temp_new[8:11]).strip() + points2 = (temp_new[11:14]).strip() + fouls1 = temp_new[15] + fouls2 = temp_new[16] + new_data[0]["points1"] = points1 + new_data[0]["points2"] = points2 + new_data[0]["foul1"] = fouls1 + new_data[0]["foul2"] = fouls2 + new_data[0]["quarter"] = quarter + + path_pic = r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators" + attack_display = temp_new[51:53] + if attack_display == "30": + time_attack = "" + path_pic = path_pic + "\\24Sec_empty.png" + else: + word_to_int = "ABCDEFGHI@" + time_attack_temp = temp_new[48:50] + # print(time_attack_temp) + # print(word_to_int.index(time_attack_temp[1])+1 if time_attack_temp[1] != '@' else '0') + if time_attack_temp[1] in word_to_int: + time_attack = f"{time_attack_temp[0]}.{word_to_int.index(time_attack_temp[1])+1 if time_attack_temp[1] != '@' else '0'}" + path_pic = path_pic + "\\24Sec_Red.png" + else: + time_attack = ( + int(time_attack_temp) + if time_attack_temp != " " + else time_attack_temp + ) + path_pic = path_pic + "\\24Sec_Orange.png" + if time_attack == "0.0": + time_attack = "" + path_pic = path_pic + "\\24Sec_empty.png" + if timer_str == "0:00": + timer_str = "0.0" + + new_data[0]["timeGFX"] = timer_str + new_data[0]["time_attackGFX"] = time_attack + new_data[0]["time_attac_pic"] = path_pic + + print(new_data[0]["timeGFX"], new_data[0]["time_attackGFX"]) + try: + with open(PATH, "w", encoding="utf-8") as file: + json.dump(new_data, file, ensure_ascii=False, indent=4) + except Exception: + print(Exception) + pass + # logging.debug(new_data) + except Exception as ex: + print(ex) + pass + + +def read_logs(): + with open( + r"C:\Users\soule\Downloads\Telegram Desktop\timer_Megasport_Nport_2024-03-05_20-00-17.log", + "r", + ) as file: + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = eval(parts[1]) + if b"\xf83" in data or b"\xf88" in data or b"\xf87" in data: + parse(data) + time.sleep(0.1) + + +def main(): + current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_Megasport_Nport_{current_time}.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + new_data = { + "timeGFX": "0.0", + "time_attackGFX": "", + "quarter": "0", + "points1": "0", + "points2": "0", + "foul1": "0", + "foul2": "0", + "foul_pic1": "", + "foul_pic2": "", + "time_attac_pic": "", + } + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + logging.debug(data) + # if b"\xf83" in data or b"\xf88" in data or b"\xf87" in data: + parse(data) + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + # read_logs() + except KeyboardInterrupt: + sys.exit(1) diff --git a/timer_stramatel.py b/timer_stramatel.py new file mode 100644 index 0000000..0bc3237 --- /dev/null +++ b/timer_stramatel.py @@ -0,0 +1,160 @@ +import sys +import json +from socket import * +from datetime import datetime +import logging +import os +import time + +SETTING = "19200,RS-485" +HOST = "192.168.127.254" +PORT = 1993 +PATH = ( + r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\python\JSON\timer_basketball.json" +) + + +def parse(line): + if len(line) > 6: + try: + with open(PATH, "r", encoding="utf-8") as f: + new_data = json.load(f) + timer_bool = 0 + if b"\xf87" in line: + temp_new = str(line.split(b"\xf87")[1]) + elif b"\xf88" in line: + temp_new = str(line.split(b"\xf88")[1]) + elif b"\xf83" in line: + temp_new = str(line.split(b"\xf83")[1]) + timer_bool = 1 + print(line) + timer_temp = temp_new[4:8] + # print(str(timer_temp) == '\\xf2') + if timer_temp != "\\xf2": + if timer_temp[-1] != " ": + minutes = int(timer_temp[:2]) + seconds = timer_temp[2:] + timer_str = f"{minutes}:{seconds}" + else: + seconds = int(timer_temp[0:2]) + milliseconds = int(timer_temp[2:]) + timer_str = f"{seconds}.{milliseconds}" + if timer_bool == 1: + quarter = temp_new[14] + points1 = (temp_new[8:11]).strip() + points2 = (temp_new[11:14]).strip() + fouls1 = temp_new[15] + fouls2 = temp_new[16] + new_data[0]["points1"] = points1 + new_data[0]["points2"] = points2 + new_data[0]["foul1"] = fouls1 + new_data[0]["foul2"] = fouls2 + new_data[0]["quarter"] = quarter + + path_pic = r"D:\ГРАФИКА\БАСКЕТБОЛ\ЕДИНАЯ ЛИГА ВТБ 2022-2023\Scorebug Indicators" + attack_display = temp_new[51:53] + if attack_display == "30": + time_attack = "" + path_pic = path_pic + "\\24Sec_empty.png" + else: + word_to_int = "ABCDEFGHI@" + time_attack_temp = temp_new[48:50] + # print(time_attack_temp) + # print(word_to_int.index(time_attack_temp[1])+1 if time_attack_temp[1] != '@' else '0') + if time_attack_temp[1] in word_to_int: + time_attack = f"{time_attack_temp[0]}.{word_to_int.index(time_attack_temp[1])+1 if time_attack_temp[1] != '@' else '0'}" + path_pic = path_pic + "\\24Sec_Red.png" + else: + time_attack = ( + int(time_attack_temp) + if time_attack_temp != " " + else time_attack_temp + ) + path_pic = path_pic + "\\24Sec_Orange.png" + if time_attack == "0.0": + time_attack = "" + path_pic = path_pic + "\\24Sec_empty.png" + if timer_str == "0:00": + timer_str = "0.0" + + new_data[0]["timeGFX"] = timer_str + new_data[0]["time_attackGFX"] = time_attack + new_data[0]["time_attac_pic"] = path_pic + + print(new_data[0]["timeGFX"], new_data[0]["time_attackGFX"]) + try: + with open(PATH, "w", encoding="utf-8") as file: + json.dump(new_data, file, ensure_ascii=False, indent=4) + except Exception: + print(Exception) + pass + # logging.debug(new_data) + except Exception as ex: + print(ex) + pass + + +def read_logs(): + with open( + r"C:\Users\soule\Downloads\Telegram Desktop\timer_Megasport_Nport_2024-03-05_20-00-17.log", + "r", + ) as file: + for line in file: + parts = line.strip().split(" DEBUG ") + if len(parts) == 2: + timestamp = parts[0][1:] + data = eval(parts[1]) + if b"\xf83" in data or b"\xf88" in data or b"\xf87" in data: + parse(data) + time.sleep(0.1) + + +def main(): + current_time = datetime.now().strftime("%Y-%m-%d_%H-%M-%S") + if not os.path.isdir("LOGS"): + os.mkdir("LOGS") + + LogFileName = f"LOGS/timer_Megasport_Nport_{current_time}.log" + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + filename=LogFileName, + filemode="w", + ) + new_data = { + "timeGFX": "0.0", + "time_attackGFX": "", + "quarter": "0", + "points1": "0", + "points2": "0", + "foul1": "0", + "foul2": "0", + "foul_pic1": "", + "foul_pic2": "", + "time_attac_pic": "", + } + with open(PATH, "w", encoding="utf-8") as file: + json.dump([new_data], file, ensure_ascii=False, indent=4) + + try: + tcp_socket = socket(AF_INET, SOCK_STREAM) + tcp_socket.connect((HOST, PORT)) + data = str.encode("hello") + tcp_socket.send(data) + data = bytes.decode(data) + while True: + data = tcp_socket.recv(1024) + logging.debug(data) + if b"\xf83" in data or b"\xf88" in data or b"\xf87" in data: + parse(data) + except KeyboardInterrupt: + tcp_socket.close() + sys.exit(1) + + +if __name__ == "__main__": + try: + main() + # read_logs() + except KeyboardInterrupt: + sys.exit(1)