This repository has been archived on 2025-02-25. You can view files and clone it, but cannot push or open issues or pull requests.
gitea 7143a19fa1 v0.1.7.0(2024/06/26)-初步可用
1. [aio.py] 在detect_network函数中需改查询时间间隔是1s,在tabview_click中增加textbox配置normal的语句
2. [do_brake.py -> btn_functions.py] 新增执行相应函数,并在get_state函数中设置无示教器模式
3. [openapi.py] 新增sock_conn函数,并做连接时的异常处理,新增类参数w2t
4. [aio.py] 修改customtkinter库中C:\Users\Administrator\AppData\Local\Programs\Python\Python312\Lib\site-packages\customtkinter\windows\widgets\ctk_tabview.py文件,参考https://github.com/TomSchimansky/CustomTkinter/issues/2296,实现修改tabview组件的字体大小,使用原生字体,同时将segmented button字体修改为原生,为了解决segmented button在禁用和启用时,屏幕抖动的问题,并将大小修改为16
5. [aio.py] 修改了segmented_button_callback的实现逻辑,使代码更简洁
6. [aio.py] 修改了在tabview_click函数中对于实例化openapi的动作,使每次切换标签都会重新实例化,也就是每次都会重新连接,修复显示不正确的问题
7. [openapi.py] 新增了socket关闭的函数,并增加msg_id为None的处理逻辑
8. [btn_functions.py] 完善了状态获取的功能,新增告警获取以及功能切换的逻辑
2024-06-26 19:54:51 +08:00

281 lines
10 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import json
import socket
import threading
import selectors
import time
import os
MAX_FRAME_SIZE = 1024
socket.setdefaulttimeout(2)
current_path = os.path.dirname(__file__)
class HmiRequest(object):
def __init__(self, w2t):
super().__init__()
self.w2t = w2t
self.c = None
self.c_xs = None
def sock_conn():
# while True:
with open(f"{current_path}/../../assets/templates/heartbeat", "r", encoding='utf-8') as f_h:
connection_state = f_h.read().strip()
if connection_state == '0':
try:
c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c.connect(('192.168.0.160', 5050))
# c.connect(('192.168.84.129', 5050))
c.setblocking(False)
c_xs = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
c_xs.connect(('192.168.0.160', 6666))
# c_xs.connect(('192.168.84.129', 6666))
c_xs.setblocking(False)
self.w2t("Connection success", 0, 0, 'green')
with open(f"{current_path}/../../assets/templates/heartbeat", "w", encoding='utf-8') as f_h:
f_h.write('1')
return c, c_xs
except Exception as Err:
with open(f"{current_path}/../../assets/templates/heartbeat", "w", encoding='utf-8') as f_h:
f_h.write('0')
self.w2t("Connection failed...", 0, 0, 'red')
return None, None
self.c, self.c_xs = sock_conn()
if self.c is None or self.c_xs is None:
self.w2t("Aborting! Try to switch tabs to re-connect!", 0, 1, 'red')
self.c_msg = []
self.c_msg_xs = []
self.flag = 0
self.response = ''
self.leftover = 0
self.flag_xs = 0
self.response_xs = ''
self.t_heartbeat = threading.Thread(target=self.heartbeat)
self.t_heartbeat.daemon = True
self.t_heartbeat.start()
self.t_unpackage = threading.Thread(target=self.unpackage, args=(self.c, ))
self.t_unpackage.daemon = True
self.t_unpackage.start()
self.t_unpackage_xs = threading.Thread(target=self.unpackage_xs, args=(self.c_xs, ))
self.t_unpackage_xs.daemon = True
self.t_unpackage_xs.start()
def close_sock(self):
self.c.close()
self.c_xs.close()
def header_check(self, index, data):
try:
_frame_size = int.from_bytes(data[index:index+2], byteorder='big')
_pkg_size = int.from_bytes(data[index+2:index+6], byteorder='big')
_protocol = int.from_bytes(data[index+6:index+7], byteorder='big')
_reserved = int.from_bytes(data[index+7:index+8], byteorder='big')
if _reserved == 0 and _protocol == 2:
return index+8, _frame_size, _pkg_size
else:
print("数据有误,需要确认")
return 'DATA ERR'
except Exception as Err:
print(f"Err = {Err}")
print("无法读取数据,需要确认")
return 'DATA READ ERR'
def heartbeat(self):
while True:
_id = self.excution('controller.heart')
_flag = 0 if self.get_from_id(_id) is None else 1
with open(f"{current_path}/../../assets/templates/heartbeat", "w", encoding='utf-8') as f_h:
f_h.write(str(_flag))
time.sleep(3)
def msg_storage(self, response, flag=0):
messages = self.c_msg if flag == 0 else self.c_msg_xs
if len(messages) < 1000:
messages.insert(0, response)
else:
messages.insert(0, response)
while len(messages) > 1000:
messages.pop()
def get_response(self, data):
_index = 0
while _index < len(data):
if self.flag == 0:
_index, _frame_size, _pkg_size = self.header_check(_index, data)
if _pkg_size <= len(data) - _index:
# 说明剩余部分的数据正好就是完整的包数据
self.response = data[_index:_index+_pkg_size].decode()
self.msg_storage(flag=0, response=self.response)
_index += _pkg_size
self.flag = 0
self.response = ''
self.leftover = 0
elif _pkg_size > len(data) - _index:
# 说有有分包的情况发生了需要flag=1的处理
self.flag = 1
self.response = data[_index:].decode()
self.leftover = _frame_size - 6 - (len(data) - _index) # 其实就是常量 2其中 6 就是六个字节的包头
break
elif self.flag == 1:
# 处理完之后将flag重置为0
_index = self.leftover
self.response += data[:_index].decode()
_index += 2
_frame_size = int.from_bytes(data[_index - 2:_index], byteorder='big')
if _frame_size == 0:
self.msg_storage(flag=0, response=self.response)
self.flag = 0
self.response = ''
self.leftover = 0
break
if _frame_size == MAX_FRAME_SIZE:
self.leftover = MAX_FRAME_SIZE - (len(data) - _index)
self.response += data[_index:].decode()
break
else:
if _index+_frame_size <= MAX_FRAME_SIZE:
self.response += data[_index:_index+_frame_size].decode()
self.msg_storage(flag=0, response=self.response)
self.flag = 0
self.response = ''
self.leftover = 0
break
else:
self.response += data[_index:].decode()
self.leftover = _index + _frame_size - MAX_FRAME_SIZE
break
def get_response_xs(self, data):
if self.flag_xs == 0:
if data[-1].decode() == '\r':
_responses = data.decode().split('\r')
for _response in _responses:
self.msg_storage(flag=1, response=_response)
else:
_responses = data.decode().split('\r')
for _response in _responses[:-1]:
if not _response:
break
self.msg_storage(flag=1, response=_response)
self.response_xs = _responses[-1]
self.flag_xs = 1
else:
if data[-1].decode() == '\r':
_responses = (self.response_xs.encode() + data).decode().split('\r')
for _response in _responses:
self.msg_storage(flag=1, response=_response)
self.response_xs = ''
self.flag_xs = 0
else:
_responses = (self.response_xs.encode() + data).decode().split('\r')
for _response in _responses[:-1]:
if not _response:
break
self.msg_storage(flag=1, response=_response)
self.response_xs = _responses[-1]
self.flag_xs = 1
def get_from_id(self, msg_id, flag=0):
messages = self.c_msg if flag == 0 else self.c_msg_xs
for i in range(3):
for msg in messages:
if msg_id is None:
self.w2t("未能成功获取到 message id...", 0, 10, 'red')
if msg_id in msg:
return msg
time.sleep(1)
else:
return None
def package(self, cmd):
_frame_head = (len(cmd)+6).to_bytes(length=2, byteorder='big')
_pkg_head = len(cmd).to_bytes(length=4, byteorder='big')
_protocol = int(2).to_bytes(length=1, byteorder='big')
_reserved = int(0).to_bytes(length=1, byteorder='big')
return _frame_head + _pkg_head + _protocol + _reserved + cmd.encode()
def package_xs(self, cmd):
return f"{json.dumps(cmd, separators=(',', ':'))}\r".encode()
def unpackage(self, sock):
def to_read(conn):
data = conn.recv(MAX_FRAME_SIZE)
if data:
# print(data)
self.get_response(data)
else:
print('closing', sock)
sel.unregister(conn)
conn.close()
sel = selectors.DefaultSelector()
sel.register(sock, selectors.EVENT_READ, to_read)
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj)
def unpackage_xs(self, sock):
def to_read(conn):
data = conn.recv(1024) # Should be ready
if data:
# print(data)
self.get_response_xs(data)
else:
print('closing', sock)
sel.unregister(conn)
conn.close()
sel = selectors.DefaultSelector()
sel.register(sock, selectors.EVENT_READ, to_read)
while True:
events = sel.select()
for key, mask in events:
callback = key.data
callback(key.fileobj)
def gen_id(self, command):
_now = time.time()
_id = f"{command}-{_now}"
return _id
def excution(self, command, flg=0, **kwargs):
if flg == 0: # for old protocols
req = None
try:
with open(f'{current_path}/../../assets/templates/{command}.json', encoding='utf-8', mode='r') as f_json:
req = json.load(f_json)
except:
print(f"暂不支持 {command} 功能,或确认该功能存在...")
return 'NOT SUPPORT'
match command:
case 'state.set_tp_mode':
req['data']['tp_mode'] = kwargs['tp_mode']
case 1:
pass
req['id'] = self.gen_id(command)
print(f"req = {req}")
cmd = json.dumps(req, separators=(',', ':'))
self.c.send(self.package(cmd))
time.sleep(2)
return req['id']
else: # for xService
pass