diff --git a/data/Users.csv b/data/Users.csv index 35259ef..c6a79c6 100644 --- a/data/Users.csv +++ b/data/Users.csv @@ -1,2 +1,2 @@ Student_Name,Student_PRN,Student_Email,Student_Whatsapp_no,Student_pass,Branch,Semester,ssid,Modbus_IP,Modbus_Port -测试用户,11111111,test@example.com,NULL,0000,测试,III,zhizhan-2,192.168.1.119,502 +测试用户,11111111,test@example.com,NULL,0000,测试,III,zhizhan-2,10.10.100.254,8899 diff --git a/kv/app.kv b/kv/app.kv index c367525..b8a1334 100644 --- a/kv/app.kv +++ b/kv/app.kv @@ -507,6 +507,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 color: rgba(0, 0, 59, 255) MDLabel: + id : wifi_status_text text: app.wifi_status_text font_name: "MPoppins" size_hint_x: None @@ -1542,8 +1543,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 MDActionBottomAppBarButton: icon: "chart-bell-curve-cumulative" pos_hint:{'center_x':0.85, 'center_y': 0.5} - on_press: - root.manager.current = 'real_time_curve' + on_press: root.manager.current = 'real_time_curve' # app.book_history() MDIconButton: @@ -1561,7 +1561,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 app.on_press_back_arrow() MDLabel: - text: "Reading Chronicle" + text: "测试历史" font_name: "BPoppins" font_size: "24sp" size_hint_x: None @@ -1572,7 +1572,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 MDLabel: - text: "Reflecting on Read and Returned" + text: "故障历史" font_name: "MPoppins" font_size: "18sp" size_hint_x: None @@ -2419,34 +2419,105 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 padding: "12dp" pos_hint: {'center_x': 0.5, 'center_y': 0.9} color: rgba(0, 0, 59, 255) + MDLabel: id: register_label - text: "通信超时" + text: "[u]通信超时: [/u]" # 下划线样式提示可点击 font_name: "MPoppins" font_size: "18sp" size_hint_x: None width: dp(400) padding: "12dp" pos_hint: {'center_x': 0.5, 'center_y': 0.85} - color: rgba(135, 133, 193, 255) - # 添加修改功能的输入和按钮(放在合适位置,如标签下方) - BoxLayout: - orientation: 'horizontal' - size_hint: 1, 0.1 - pos_hint: {'center_x': 0.5, 'center_y': 0.75} # 调整位置在标签下方 - padding: dp(10) - spacing: dp(10) - - MDTextField: - id: register_input - # hint_text: "modify value" - input_filter: "int" # 限制整数输入 - size_hint_x: 0.7 - - MDRaisedButton: - text: "修改" - size_hint_x: 0.3 - on_press: app.modify_register(register_input.text) # 绑定修改方法 + color: (135/255, 133/255, 193/255, 1) + markup: True # 启用标记以显示下划线 + on_touch_down: + # if self.collide_point(*args[1].pos): + app.show_modify_dialog("register_label", " ") # 与if同层级缩进 + MDLabel: + id: register_label + text: "[u]通信超时: [/u]" # 下划线样式提示可点击 + font_name: "MPoppins" + font_size: "18sp" + size_hint_x: None + width: dp(400) + padding: "12dp" + pos_hint: {'center_x': 0.5, 'center_y': 0.85} + color: (135/255, 133/255, 193/255, 1) + markup: True # 启用标记以显示下划线 + on_touch_down: + # if self.collide_point(*args[1].pos): + app.show_modify_dialog("register_label", " ") # 与if同层级缩进 + MDLabel: + id: register_label + text: "[u]通信超时: [/u]" # 下划线样式提示可点击 + font_name: "MPoppins" + font_size: "18sp" + size_hint_x: None + width: dp(400) + padding: "12dp" + pos_hint: {'center_x': 0.5, 'center_y': 0.85} + color: (135/255, 133/255, 193/255, 1) + markup: True # 启用标记以显示下划线 + on_touch_down: + # if self.collide_point(*args[1].pos): + app.show_modify_dialog("register_label", " ") # 与if同层级缩进 + MDLabel: + id: register_label + text: "[u]通信超时: [/u]" # 下划线样式提示可点击 + font_name: "MPoppins" + font_size: "18sp" + size_hint_x: None + width: dp(400) + padding: "12dp" + pos_hint: {'center_x': 0.5, 'center_y': 0.85} + color: (135/255, 133/255, 193/255, 1) + markup: True # 启用标记以显示下划线 + on_touch_down: + # if self.collide_point(*args[1].pos): + app.show_modify_dialog("register_label", " ") # 与if同层级缩进 + MDLabel: + id: register_label + text: "[u]通信超时: [/u]" # 下划线样式提示可点击 + font_name: "MPoppins" + font_size: "18sp" + size_hint_x: None + width: dp(400) + padding: "12dp" + pos_hint: {'center_x': 0.5, 'center_y': 0.85} + color: (135/255, 133/255, 193/255, 1) + markup: True # 启用标记以显示下划线 + on_touch_down: + # if self.collide_point(*args[1].pos): + app.show_modify_dialog("register_label", " ") # 与if同层级缩进 + MDLabel: + id: register_label + text: "[u]通信超时: [/u]" # 下划线样式提示可点击 + font_name: "MPoppins" + font_size: "18sp" + size_hint_x: None + width: dp(400) + padding: "12dp" + pos_hint: {'center_x': 0.5, 'center_y': 0.85} + color: (135/255, 133/255, 193/255, 1) + markup: True # 启用标记以显示下划线 + on_touch_down: + # if self.collide_point(*args[1].pos): + app.show_modify_dialog("register_label", " ") # 与if同层级缩进 + MDLabel: + id: register_label + text: "[u]通信超时: [/u]" # 下划线样式提示可点击 + font_name: "MPoppins" + font_size: "18sp" + size_hint_x: None + width: dp(400) + padding: "12dp" + pos_hint: {'center_x': 0.5, 'center_y': 0.85} + color: (135/255, 133/255, 193/255, 1) + markup: True # 启用标记以显示下划线 + on_touch_down: + # if self.collide_point(*args[1].pos): + app.show_modify_dialog("register_label", " ") # 与if同层级缩进 # CurveWidget: # size_hint_y: None # height: dp(300) diff --git a/main.py b/main.py index 0665c1b..ee15973 100644 --- a/main.py +++ b/main.py @@ -17,7 +17,7 @@ from kivymd.uix.datatables import MDDataTable import random import csv - +from kivymd.uix.textfield import MDTextField from kivymd.uix.boxlayout import MDBoxLayout from kivymd.uix.button import MDFlatButton from kivymd.uix.dialog import MDDialog @@ -137,6 +137,7 @@ class app(MDApp): self.back_button = None self.user = None self.dialog = None + self.dialog2 = None self.profile_edit_screen = None self.edit_email = None self.edit_prn = None @@ -366,23 +367,6 @@ class app(MDApp): self.register_update_event.cancel() self.register_update_event = None - def read_modbus_register(self): - """读取寄存器值(复用原逻辑)""" - if not self.modbus_master: - try: - self.modbus_master = TcpMaster(self.modbus_ip or '192.168.1.1', self.modbus_port or 502) - self.modbus_master.set_timeout(5.0) - except Exception as e: - print(f"Modbus连接失败: {e}") - return "连接失败" - - try: - result = self.modbus_master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 1) - return str(result[0]) # 返回寄存器值 - except Exception as e: - print(f"读取失败: {e}") - return "读取失败" - # def update_register_display(self, dt): # """更新原标签的显示内容""" # # 仅在目标屏幕时更新 @@ -393,33 +377,68 @@ class app(MDApp): # real_time_screen = self.root.get_screen("real_time_curve") # real_time_screen.ids.register_label.text = f"寄存器 0: {value}" # 直接更新原标签 - def write_modbus_register(self, value): - """写入寄存器值""" + def write_modbus_register(self, slave_id=1, address=0, value=None): + """ + 写入Modbus保持寄存器(单个寄存器) + :param slave_id: 从机ID(默认1) + :param address: 寄存器地址(默认0) + :param value: 要写入的值(必须为整数,16位范围内:0-65535) + :return: 操作结果字符串 + """ + # 检查Modbus连接是否初始化 if not self.modbus_master: - pass + return "错误:Modbus未连接,请先初始化连接" + + # 检查写入值是否有效 + if value is None: + return "错误:未指定要写入的值" try: - self.modbus_master.execute(1, cst.WRITE_SINGLE_REGISTER, 0, value) - return "修改成功" + # 转换为整数并检查范围(Modbus保持寄存器通常为16位无符号整数) + write_value = int(value) + if not (0 <= write_value <= 65535): + return "错误:值必须在0-65535范围内(16位无符号整数)" + except ValueError: + return "错误:写入值必须为整数" + + try: + # 使用正确的写入函数:WRITE_SINGLE_REGISTER(写入单个寄存器) + self.modbus_master.execute( + slave=slave_id, + function_code=cst.WRITE_SINGLE_REGISTER, + starting_address=address, + output_value=write_value # 注意参数名是output_value + ) + return f"成功:从机ID={slave_id},寄存器地址={address},写入值={write_value}" except Exception as e: - return f"修改失败: {e}" + # 捕获异常并返回错误信息 + error_msg = f"失败:从机ID={slave_id},寄存器地址={address},错误信息:{str(e)}" + print(error_msg) + return error_msg def modify_register(self, input_text): """处理修改请求,修改后更新原标签""" if not input_text: self.show_dialog("错误", "请输入值") return + try: value = int(input_text) - result = self.write_modbus_register(value) - self.show_dialog("结果", result) - # 若成功,立即刷新原标签显示 + # 这里假设写入 从机ID=1,地址=0 的寄存器 + # 若需要动态指定,可从界面控件中获取(例如:self.ids.slave_id.text) + result = self.write_modbus_register( + slave_id=1, + address=0, + value=value + ) + self.show_dialog("操作结果", result) + # 若成功,立即刷新显示 if "成功" in result: - self.update_register_display(0) + self.update_register_display(0) # 0是dt参数占位符 except ValueError: self.show_dialog("错误", "请输入有效整数") def show_dialog(self, title, message): - self.dialog2(title, message) + self.dialog1(message,title) #############################################@Frequently used functions################################################## @staticmethod @@ -570,42 +589,119 @@ class app(MDApp): self.dialog.open() + # MDDialog box dismiss function 'close_dialog' def close_dialog(self, *args): self.dialog.dismiss() + + #############################################Modbus Functions############################################################ - def read_modbus_register(self): - """读取Modbus寄存器值并更新界面显示""" + def show_modify_dialog(self, label_id, current_value=""): + """显示修改对话框""" + if not self.dialog2: + # 创建输入框 + self.modify_input = MDTextField( + id="modify_input", + hint_text="请输入新值", + input_filter="int", # 保持整数输入限制 + text=current_value + ) + + # 创建对话框 + self.dialog2 = MDDialog( + title="修改参数", + type="custom", + content_cls=MDBoxLayout( + self.modify_input, + orientation="vertical", + padding=dp(10), + spacing=dp(10), + size_hint_y=None, + height=dp(100) + ), + buttons=[ + MDFlatButton( + text="取消", + on_press=lambda x: self.dialog2.dismiss() + ), + MDFlatButton( + text="确认", + on_press=lambda x: self.confirm_modify(label_id) + ) + ] + ) + else: + # 重置输入框内容 + self.modify_input.text = current_value + + self.dialog2.open() + + def confirm_modify(self, label_id): + """确认修改并更新标签""" + new_value = self.modify_input.text + if new_value: # 确保输入不为空 + # 根据标签ID获取对应的标签并更新 + screen = self.root.get_screen("real_time_curve") + if label_id == "register_label" and hasattr(screen.ids, label_id): + screen.ids[label_id].text = f"通信超时: {new_value}" # 更新标签显示 + self.modify_register(new_value) # 调用原有的修改方法 + self.dialog2.dismiss() # 关闭对话框 + + def read_modbus_registers(self, slave_id, address, count): + """ + 通用的Modbus保持寄存器读取函数 + :param slave_id: 从机ID(动态传入,如1、2、3等) + :param address: 寄存器地址 + :param count: 读取的寄存器数量 + :return: 读取结果或None(失败时) + """ if not self.modbus_master: - pass + print("Modbus未初始化,请先连接") + return None try: - # 读取寄存器(1号从机,保持寄存器,地址0,长度1) - result = self.modbus_master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 1) - # 结果是元组,取第一个值 - return str(result[0]) + # 动态传入slave_id,替代固定的1 + result = self.modbus_master.execute( + slave=slave_id, + function_code=cst.READ_HOLDING_REGISTERS, + starting_address=address, + quantity_of_x=count + ) + print(f"从机ID {slave_id} 读取成功:{result}") + if result: + register_value = result[0] # 提取元组中的第一个元素(即0) + print(f"寄存器值:{register_value}") + return result except Exception as e: - pass + print(f"从机ID {slave_id} 读取失败:{e}") + return None def update_register_display(self, dt): """定时更新寄存器值显示""" - register_value = self.read_modbus_register() + register_value = self.read_modbus_registers(slave_id=1, address=0, count=1) + # 获取显示标签并更新文本 real_time_screen = self.root.get_screen("real_time_curve") # 根据实际屏幕名称调整 if hasattr(real_time_screen.ids, 'register_label'): - real_time_screen.ids.register_label.text = f"寄存器 0: {register_value}" + + if register_value is not None: + real_time_screen.ids.register_label.text = f"寄存器 0: {register_value[0]}" + else: + real_time_screen.ids.register_label.text = "寄存器 0: 读取失败或超时" ###################################LoginPageWork-Start################################################# def update_wifi_status(self, dt): self.check_wifi() - Clock.schedule_once(self.update_wifi_status, 1) # 5秒刷新一次 + Clock.schedule_once(self.update_wifi_status, 1) # 1秒刷新一次 def check_wifi(self): if platform != 'android': - self.wifi_status_text = '非Android设备' - return + login_screen = self.root.get_screen("login") # 根据实际屏幕名称调整 + if hasattr(login_screen.ids, 'wifi_status_text'): + self.wifi_status_text = '非Android设备' + return try: from jnius import autoclass, cast