858 lines
35 KiB
Python
858 lines
35 KiB
Python
|
||
from kivy.properties import ObjectProperty, StringProperty, ListProperty
|
||
from datetime import datetime, timedelta
|
||
from kivy.core.text import LabelBase
|
||
from kivy.metrics import dp
|
||
from kivy.uix.anchorlayout import AnchorLayout
|
||
from kivy.uix.boxlayout import BoxLayout
|
||
from kivy.uix.button import Button
|
||
from kivy.uix.gridlayout import GridLayout
|
||
from kivy.uix.image import Image
|
||
from kivymd.app import MDApp
|
||
from kivy.core.window import Window
|
||
from kivy.uix.screenmanager import ScreenManager
|
||
from kivy.lang import Builder
|
||
from kivy.uix.screenmanager import ScreenManager, Screen
|
||
from kivymd.uix.datatables import MDDataTable
|
||
import random
|
||
import threading
|
||
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
|
||
from kivymd.uix.label import MDLabel
|
||
from kivy.uix.label import Label
|
||
|
||
from kivy.utils import platform
|
||
from kivy.clock import Clock
|
||
from kivy.uix.widget import Widget
|
||
|
||
from kivy.graphics import Color, Rectangle
|
||
from kivy_garden.graph import Graph, LinePlot
|
||
|
||
import modbus_tk
|
||
import modbus_tk.defines as cst
|
||
import socket
|
||
from modbus_client import ModbusClient
|
||
import re
|
||
from threading import Thread
|
||
from functools import partial
|
||
from collections import defaultdict
|
||
|
||
from random import randint
|
||
from kivymd.theming import ThemeManager
|
||
|
||
LabelBase.register(name="MPoppins", fn_regular="fonts/Chinese/msyh.ttf")
|
||
LabelBase.register(name="BPoppins", fn_regular="fonts/Chinese/msyh.ttf")
|
||
LabelBase.register(name="RRubik", fn_regular="fonts/Chinese/msyh.ttf")
|
||
LabelBase.register(name="RCro", fn_regular="fonts/Chinese/msyh.ttf")
|
||
LabelBase.register(name="RPac", fn_regular="fonts/Chinese/msyh.ttf")
|
||
|
||
|
||
class MainScreen(Screen):
|
||
pass
|
||
class HomeScreen(Screen):
|
||
home = ObjectProperty(None)
|
||
class LoginScreen(Screen):
|
||
login = ObjectProperty(None)
|
||
class ProfileScreen(Screen):
|
||
profile = ObjectProperty(None)
|
||
class ProfileEditScreen(Screen):
|
||
profile_edit = ObjectProperty(None)
|
||
class HistoryScreen(Screen):
|
||
history = ObjectProperty(None)
|
||
|
||
class ModifyCurrentParamScreen(Screen):
|
||
modify_current_param = ObjectProperty(None)
|
||
class ModifyVoltageParamScreen(Screen):
|
||
modify_voltage_param = ObjectProperty(None)
|
||
class ModifyLeakageParamScreen(Screen):
|
||
modify_leakage_param = ObjectProperty(None)
|
||
class ModifySystemParamScreen(Screen):
|
||
modify_system_param = ObjectProperty(None)
|
||
class ModifyProtectionParamScreen(Screen):
|
||
modify_protection_param = ObjectProperty(None)
|
||
class RealTimeCurveScreen(Screen):
|
||
real_time_curve = ObjectProperty(None)
|
||
class ControlCommandScreen(Screen):
|
||
control_command = ObjectProperty(None)
|
||
class AboutScreen(Screen):
|
||
about = ObjectProperty(None)
|
||
|
||
|
||
# Window.size = (dp(360), dp(680))
|
||
|
||
class app(MDApp):
|
||
wifi_status_text = StringProperty("")
|
||
def __init__(self):
|
||
super().__init__()
|
||
self.signup_branch = None
|
||
self.user_name = None
|
||
|
||
|
||
|
||
self.rec_grid = None
|
||
self.recommend_screen = None
|
||
self.book_input = None
|
||
self.data_tables = None
|
||
self.search_grid = None
|
||
self.search_field = None
|
||
self.renew_grid = None
|
||
self.renewable_books = []
|
||
self.renew = self.renewable_books
|
||
self.history_grid = None
|
||
self.books_history = []
|
||
self.history = self.books_history
|
||
self.image_label_grid = None
|
||
self.books = []
|
||
self.items = self.books
|
||
self.book_name = None
|
||
self.isbn = None
|
||
self.a = None
|
||
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
|
||
self.edit_name = None
|
||
self.edit_wifi_ssid = None
|
||
self.edit_branch = None
|
||
self.profile_semester = None
|
||
self.profile_branch = None
|
||
self.profile_wifi_ssid = None
|
||
self.profile_prn = None
|
||
self.profile_user_pass = None
|
||
self.profile_user_name = None
|
||
self.user_no = None
|
||
self.user_email = None
|
||
self.user_prn = None
|
||
self.d2 = None
|
||
self.d3 = None
|
||
self.d4 = None
|
||
self.user_pass = None
|
||
self.d1 = None
|
||
self.edit_semester = None
|
||
self.otp_button = None
|
||
self.new_pass = None
|
||
self.new_pass1 = None
|
||
self.mobile_no = None
|
||
self.password = None
|
||
self.username = None
|
||
|
||
self.modbus_master = ModbusClient() # Modbus连接对象
|
||
self.modbus_ip = None # Modbus服务器IP
|
||
self.modbus_port = None # Modbus服务器端口
|
||
|
||
|
||
self.theme_cls.font_styles["H1"] = ["BPoppins", 96, False, -1.5]
|
||
self.theme_cls.font_styles["H2"] = ["BPoppins", 60, False, -0.5]
|
||
self.theme_cls.font_styles["H3"] = ["BPoppins", 48, False, 0]
|
||
self.theme_cls.font_styles["H4"] = ["BPoppins", 34, False, 0.25]
|
||
self.theme_cls.font_styles["H5"] = ["BPoppins", 25, False, 0.15]
|
||
self.theme_cls.font_styles["H6"] = ["BPoppins", 16, False, 0.15]
|
||
self.theme_cls.font_styles["Subtitle1"] = ["BPoppins", 16, False, 0.15]
|
||
self.theme_cls.font_styles["Subtitle2"] = ["BPoppins", 14, False, 0.1]
|
||
self.theme_cls.font_styles["Body1"] = ["BPoppins", 16, False, 0.5]
|
||
self.theme_cls.font_styles["Body2"] = ["BPoppins", 14, False, 0.25]
|
||
self.theme_cls.font_styles["Button"] = ["BPoppins", 14, True, 1.25]
|
||
self.theme_cls.font_styles["Caption"] = ["BPoppins", 13, False, 0.15]
|
||
self.theme_cls.font_styles["Overline"] = ["BPoppins", 10, True, 1.5]
|
||
|
||
def build(self):
|
||
Builder.load_file('kv/app.kv')
|
||
screen_manager = ScreenManager()
|
||
screen_manager.add_widget(MainScreen(name="main"))
|
||
screen_manager.add_widget(HomeScreen(name="home"))
|
||
screen_manager.add_widget(LoginScreen(name="login"))
|
||
screen_manager.add_widget(HistoryScreen(name="history"))
|
||
screen_manager.add_widget(ProfileScreen(name="profile"))
|
||
screen_manager.add_widget(ProfileEditScreen(name="profile_edit"))
|
||
|
||
screen_manager.add_widget(ModifyCurrentParamScreen(name="modify_current_param"))
|
||
screen_manager.add_widget(ModifyVoltageParamScreen(name="modify_voltage_param"))
|
||
screen_manager.add_widget(ModifyLeakageParamScreen(name="modify_leakage_param"))
|
||
screen_manager.add_widget(ModifySystemParamScreen(name="modify_system_param"))
|
||
screen_manager.add_widget(ModifyProtectionParamScreen(name="modify_protection_param"))
|
||
screen_manager.add_widget(RealTimeCurveScreen(name="real_time_curve"))
|
||
screen_manager.add_widget(ControlCommandScreen(name="control_command"))
|
||
screen_manager.add_widget(AboutScreen(name="about"))
|
||
|
||
# 添加其他屏幕
|
||
|
||
|
||
return screen_manager
|
||
|
||
#############################################ALL INPUT TEXT############################################################
|
||
def on_start(self):
|
||
|
||
# 从根窗口中获取名为"login"的屏幕(登录界面)
|
||
login_screen = self.root.get_screen("login")
|
||
|
||
|
||
# 从根窗口中获取名为"home"的屏幕(主界面)
|
||
home_screen = self.root.get_screen("home")
|
||
# 通过界面ID获取主界面中的用户信息组件
|
||
self.user = home_screen.ids.user
|
||
|
||
# 从根窗口中获取名为"profile"的屏幕(个人资料界面)
|
||
profile_screen = self.root.get_screen("profile")
|
||
# 通过界面ID获取个人资料界面中的姓名展示组件
|
||
self.profile_user_name = profile_screen.ids.profile_user_name
|
||
# 通过界面ID获取个人资料界面中的邮箱展示组件
|
||
self.profile_user_pass = profile_screen.ids.profile_user_pass
|
||
# 通过界面ID获取个人资料界面中的PRN(身份标识)展示组件
|
||
self.profile_prn = profile_screen.ids.profile_prn
|
||
# 通过界面ID获取个人资料界面中的手机号展示组件
|
||
self.profile_wifi_ssid = profile_screen.ids.profile_wifi_ssid
|
||
# 通过界面ID获取个人资料界面中的所属部门/专业展示组件
|
||
self.profile_branch = profile_screen.ids.profile_branch
|
||
# 通过界面ID获取个人资料界面中的年级/学期展示组件
|
||
self.profile_semester = profile_screen.ids.profile_semester
|
||
# 从根窗口中获取名为"profile_edit"的屏幕(个人资料编辑界面)
|
||
self.profile_edit_screen = self.root.get_screen("profile_edit")
|
||
# 通过界面ID获取资料编辑界面中的姓名编辑输入框组件
|
||
self.edit_name = self.profile_edit_screen.ids.edit_name
|
||
# 通过界面ID获取资料编辑界面中的邮箱编辑输入框组件
|
||
self.edit_email = self.profile_edit_screen.ids.edit_email
|
||
# 通过界面ID获取资料编辑界面中的PRN(身份标识)编辑输入框组件
|
||
self.edit_prn = self.profile_edit_screen.ids.edit_prn
|
||
# 通过界面ID获取资料编辑界面中的手机号编辑输入框组件
|
||
self.edit_wifi_ssid = self.profile_edit_screen.ids.edit_no
|
||
# 通过界面ID获取资料编辑界面中的所属部门/专业编辑选择组件
|
||
self.edit_branch = self.profile_edit_screen.ids.edit_branch
|
||
# 通过界面ID获取资料编辑界面中的年级/学期编辑选择组件
|
||
self.edit_semester = self.profile_edit_screen.ids.edit_sem
|
||
|
||
|
||
self.root.bind(current=self.on_screen_changed)
|
||
self.register_update_event = None
|
||
self.wifi_update_event = None
|
||
|
||
def on_screen_changed(self, instance, value):
|
||
"""屏幕切换时启动/停止刷新"""
|
||
if value == "real_time_curve":
|
||
# 进入目标屏幕时启动定时刷新
|
||
if not self.register_update_event:
|
||
self.register_update_event = Clock.schedule_interval(self.update_register_display, 1)
|
||
else:
|
||
# 离开时停止刷新
|
||
if self.register_update_event:
|
||
self.register_update_event.cancel()
|
||
self.register_update_event = None
|
||
|
||
if value == "login":
|
||
if not self.wifi_update_event:
|
||
self.wifi_update_event = Clock.schedule_interval(self.update_wifi_status, 1)
|
||
else:
|
||
if self.wifi_update_event:
|
||
self.wifi_update_event.cancel()
|
||
self.wifi_update_event = None
|
||
|
||
#############################################@Frequently used functions##################################################
|
||
|
||
@staticmethod
|
||
def change_cursor(is_enter):
|
||
"""改变鼠标指针样式"""
|
||
# 如果is_enter为True(鼠标进入目标区域),将鼠标指针改为手型
|
||
if is_enter:
|
||
Window.set_system_cursor('hand')
|
||
# 否则(鼠标离开目标区域),将鼠标指针改回默认箭头样式
|
||
else:
|
||
Window.set_system_cursor('arrow')
|
||
|
||
@staticmethod
|
||
def toggle_password_visibility(password_field, icon_button):
|
||
"""切换密码输入框的可见性状态"""
|
||
# 检查密码输入框当前是否处于密码隐藏状态
|
||
if password_field.password:
|
||
# 如果是隐藏状态,切换为可见状态
|
||
password_field.password = False
|
||
# 更新图标为"eye"(眼睛图标,表示当前可见)
|
||
icon_button.icon = "eye"
|
||
else:
|
||
# 如果是可见状态,切换为隐藏状态(显示为圆点/星号)
|
||
password_field.password = True
|
||
# 更新图标为"eye-off"(闭眼图标,表示当前隐藏)
|
||
icon_button.icon = "eye-off"
|
||
|
||
def clear_text(self):
|
||
pass
|
||
|
||
def on_press_back_arrow(self):
|
||
pass
|
||
|
||
|
||
|
||
|
||
|
||
############################################@DIALOG BOX most used functions##############################################
|
||
# MDDialog box function 'dialog'
|
||
|
||
def dialog1(self, text, title="Tips"):
|
||
close_button = MDFlatButton(
|
||
text="关闭",
|
||
font_name="MPoppins",
|
||
on_release=self.close_dialog
|
||
)
|
||
|
||
content_label = Label(
|
||
text=text,
|
||
font_name="MPoppins",
|
||
color=(0, 0, 0, 1),
|
||
size_hint_y=None,
|
||
height=dp(30),
|
||
halign="center",
|
||
valign="middle"
|
||
)
|
||
content_label.bind(size=content_label.setter('text_size'))
|
||
|
||
self.dialog = MDDialog(
|
||
title=title,
|
||
type="custom",
|
||
content_cls=content_label,
|
||
size_hint=(0.84, None),
|
||
buttons=[close_button]
|
||
)
|
||
self.dialog.open()
|
||
def dialog2(self, title, text):
|
||
close_button = MDFlatButton(
|
||
text="关闭",
|
||
font_name="MPoppins",
|
||
on_release=self.close_dialog
|
||
)
|
||
|
||
content_label = Label(
|
||
text=text,
|
||
font_name="MPoppins",
|
||
color=(0, 0, 0, 1),
|
||
size_hint_y=None,
|
||
height=dp(30),
|
||
halign="center",
|
||
valign="middle"
|
||
)
|
||
content_label.bind(size=content_label.setter('text_size'))
|
||
|
||
self.dialog = MDDialog(
|
||
title=title,
|
||
type="custom",
|
||
content_cls=content_label,
|
||
size_hint=(0.84, None),
|
||
buttons=[close_button]
|
||
)
|
||
self.dialog.open()
|
||
|
||
|
||
|
||
# MDDialog box dismiss function 'close_dialog'
|
||
def close_dialog(self, *args):
|
||
self.dialog.dismiss()
|
||
|
||
|
||
|
||
#############################################Modbus Functions############################################################
|
||
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):
|
||
"""确认修改并更新标签,增强鲁棒性"""
|
||
try:
|
||
new_value = self.modify_input.text
|
||
if not new_value:
|
||
self.show_dialog("错误", "请输入新值")
|
||
return
|
||
|
||
screen = self.root.get_screen("real_time_curve")
|
||
label = screen.ids.get(label_id, None)
|
||
if label:
|
||
label.text = f"通信超时: {new_value}"
|
||
# 调用原有的修改方法,增加异常捕获
|
||
try:
|
||
self.modify_register(new_value)
|
||
except Exception as e:
|
||
self.show_dialog("错误", f"寄存器修改失败:{e}")
|
||
else:
|
||
self.show_dialog("错误", "未找到目标标签")
|
||
except Exception as e:
|
||
self.show_dialog("错误", f"操作异常:{e}")
|
||
finally:
|
||
if self.dialog2:
|
||
self.dialog2.dismiss()
|
||
|
||
def read_modbus_registers(self, slave_id=1, address=0, count=1):
|
||
"""
|
||
通用的Modbus保持寄存器读取函数(优化版)
|
||
:param slave_id: 从机ID
|
||
:param address: 寄存器地址
|
||
:param count: 读取数量
|
||
:return: {'success': bool, 'data': list, 'msg': str}
|
||
"""
|
||
return self.modbus_master.read_holding_registers(slave_id, address, count)
|
||
|
||
def modify_register(self, field_widget, input_text):
|
||
"""
|
||
用户主动修改时,写入指定寄存器并刷新显示
|
||
:param field_widget: MDTextField控件对象
|
||
:param input_text: 用户输入的值
|
||
"""
|
||
address = getattr(field_widget, 'comm_address', None)
|
||
slave_id = 1 # 可根据实际情况动态获取
|
||
if address is None:
|
||
self.show_dialog("错误", "未设置通讯地址")
|
||
return
|
||
if not input_text:
|
||
self.show_dialog("错误", "请输入值")
|
||
return
|
||
try:
|
||
value = int(input_text)
|
||
result = self.write_modbus_register(slave_id=slave_id, address=address, value=value)
|
||
# self.show_dialog("操作结果", result)
|
||
self.update_register_display(0)
|
||
except ValueError:
|
||
self.show_dialog("错误", "请输入有效整数")
|
||
|
||
def write_modbus_register(self, slave_id=1, address=0, value=None):
|
||
"""
|
||
通用写入Modbus保持寄存器(单个寄存器),低耦合版
|
||
:param slave_id: 从机ID
|
||
:param address: 寄存器地址
|
||
:param value: 要写入的值(整数,0-65535)
|
||
:return: {'success': bool, 'msg': str}
|
||
"""
|
||
return self.modbus_master.write_single_register(slave_id, address, value)
|
||
|
||
def show_dialog(self, title, message):
|
||
self.dialog1(message,title)
|
||
|
||
def update_register_display(self, dt):
|
||
real_time_screen = self.root.get_screen("real_time_curve")
|
||
widgets = [w for w in real_time_screen.ids.values()
|
||
if isinstance(w, MDTextField) and hasattr(w, 'comm_address')]
|
||
|
||
# 收集未聚焦的寄存器地址
|
||
addr_widget_map = {}
|
||
for w in widgets:
|
||
if not w.focus:
|
||
addr = getattr(w, 'comm_address', None)
|
||
if addr is not None:
|
||
addr_widget_map[addr] = w
|
||
|
||
if not addr_widget_map:
|
||
return
|
||
|
||
# 分组连续地址段(例如 [1,2,3,10,11,12] -> [[1,2,3], [10,11,12]])
|
||
sorted_addresses = sorted(addr_widget_map.keys())
|
||
grouped_ranges = []
|
||
group = [sorted_addresses[0]]
|
||
|
||
for addr in sorted_addresses[1:]:
|
||
if addr == group[-1] + 1:
|
||
group.append(addr)
|
||
else:
|
||
grouped_ranges.append(group)
|
||
group = [addr]
|
||
grouped_ranges.append(group)
|
||
|
||
# 开启线程异步读取每段
|
||
for group in grouped_ranges:
|
||
start = group[0]
|
||
count = group[-1] - start + 1
|
||
thread = Thread(target=self._read_and_update_range, args=(start, count, group, addr_widget_map))
|
||
thread.start()
|
||
|
||
def _read_and_update_range(self, start, count, group, addr_widget_map):
|
||
try:
|
||
result = self.read_modbus_registers(slave_id=1, address=start, count=count)
|
||
except Exception as e:
|
||
result = {'success': False, 'error': str(e)}
|
||
|
||
# 在主线程中更新 UI
|
||
Clock.schedule_once(partial(self._update_widgets_with_data, start, group, addr_widget_map, result), 0)
|
||
|
||
def _update_widgets_with_data(self, start, group, addr_widget_map, result, dt):
|
||
if result.get('success') and result.get('data'):
|
||
data = result['data']
|
||
for addr in group:
|
||
widget = addr_widget_map.get(addr)
|
||
index = addr - start
|
||
if widget and 0 <= index < len(data):
|
||
new_value = str(data[index])
|
||
if widget.text != new_value:
|
||
widget.text = new_value
|
||
elif widget:
|
||
widget.text = "索引错误"
|
||
else:
|
||
for addr in group:
|
||
widget = addr_widget_map.get(addr)
|
||
if widget:
|
||
widget.text = f"失败: {result.get('error', '读取失败')}"
|
||
|
||
###################################LoginPageWork-Start#################################################
|
||
|
||
def update_wifi_status(self, dt):
|
||
# 只有当前屏幕为 login 时才更新
|
||
if self.root.current != "login":
|
||
return
|
||
|
||
if platform != 'android':
|
||
self.wifi_status_text = '非Android设备'
|
||
return
|
||
|
||
try:
|
||
from jnius import autoclass, cast
|
||
|
||
PythonActivity = autoclass('org.kivy.android.PythonActivity')
|
||
Context = autoclass('android.content.Context')
|
||
activity = PythonActivity.mActivity
|
||
|
||
WifiManager = autoclass('android.net.wifi.WifiManager')
|
||
Formatter = autoclass('android.text.format.Formatter')
|
||
|
||
wifi_service = activity.getSystemService(Context.WIFI_SERVICE)
|
||
wifi_manager = cast('android.net.wifi.WifiManager', wifi_service)
|
||
|
||
if not wifi_manager.isWifiEnabled():
|
||
self.wifi_status_text = 'WiFi 未启用'
|
||
return
|
||
|
||
wifi_info = wifi_manager.getConnectionInfo()
|
||
if wifi_info is None:
|
||
self.wifi_status_text = 'WiFi 信息不可用'
|
||
return
|
||
|
||
ssid = wifi_info.getSSID()
|
||
ssid_display = ssid.strip('"') if ssid else "SSID Unknown"
|
||
|
||
ip_int = wifi_info.getIpAddress()
|
||
ip_str = Formatter.formatIpAddress(ip_int) if ip_int != 0 else "0.0.0.0"
|
||
link_speed = wifi_info.getLinkSpeed() # Mbps
|
||
bssid = wifi_info.getBSSID()
|
||
rssi = wifi_info.getRssi()
|
||
|
||
self.wifi_status_text = (
|
||
f'SSID: {ssid_display}\n'
|
||
f'IP: {ip_str}\n'
|
||
f'速度: {link_speed} Mbps\n'
|
||
f'BSSID: {bssid}\n'
|
||
f'信号: {rssi} dBm'
|
||
)
|
||
|
||
except Exception as e:
|
||
self.wifi_status_text = f'获取WiFi信息失败\n{e}'
|
||
|
||
def verify(self, obj=None):
|
||
try:
|
||
if platform == "android":
|
||
from jnius import autoclass
|
||
PythonActivity = autoclass('org.kivy.android.PythonActivity')
|
||
Context = autoclass('android.content.Context')
|
||
activity = PythonActivity.mActivity
|
||
wifi_service = activity.getSystemService(Context.WIFI_SERVICE)
|
||
wifi_info = wifi_service.getConnectionInfo()
|
||
# 获取当前连接的WiFi名称并处理引号和大小写
|
||
wifi_id = wifi_info.getSSID().strip('"').lower()
|
||
else:
|
||
# 非Android平台使用模拟WiFi
|
||
wifi_id = "zhizhan-2"
|
||
except Exception as e:
|
||
self.dialog1(f"获取WiFi信息失败:{e}")
|
||
return
|
||
|
||
try:
|
||
with open("data/Users.csv", "r", encoding="utf-8") as file:
|
||
# 使用DictReader读取CSV,通过列名访问数据
|
||
csv_reader = csv.DictReader(file)
|
||
|
||
for row in csv_reader:
|
||
# 获取CSV中存储的WiFi SSID并处理大小写
|
||
csv_ssid = row['Wifi_SSID'].strip().lower()
|
||
|
||
# 精确匹配WiFi SSID
|
||
if wifi_id == csv_ssid:
|
||
# 通过列名获取用户信息
|
||
name = row['User']
|
||
prn = row['Reserve'] # 根据实际列名调整
|
||
email = row['Reserve'] # 根据实际列名调整
|
||
number = row['Reserve'] # 根据实际列名调整
|
||
password = row['User_pass']
|
||
branch = row['Reserve'] # 根据实际列名调整
|
||
semester = row['Reserve'] # 根据实际列名调整
|
||
|
||
# 更新界面显示的用户信息
|
||
self.root.current = "home"
|
||
self.user.text = f"[b]Hey! {name}[/b]"
|
||
self.profile_user_name.text = self.edit_name.text = name
|
||
self.profile_user_pass.text = self.edit_email.text = email
|
||
self.profile_prn.text = self.edit_prn.text = prn
|
||
self.profile_wifi_ssid.text = row['Wifi_SSID']
|
||
self.profile_semester.text = self.edit_semester.text = semester
|
||
self.profile_branch.text = self.edit_branch.text = branch
|
||
|
||
# 连接Modbus设备
|
||
self.connect_modbus()
|
||
self.dialog1(f"欢迎你,{name}!\n认证成功!")
|
||
return
|
||
except Exception as e:
|
||
self.dialog1(f"读取用户信息失败:{e}")
|
||
return
|
||
|
||
# 认证失败提示
|
||
self.dialog1("认证失败,请检查网络或确保手机权限打开定位和连接到目标WiFi")
|
||
|
||
def connect_modbus(self):
|
||
def _connect_in_background():
|
||
modbus_ip = None
|
||
modbus_port = 502
|
||
master = None
|
||
|
||
try:
|
||
# 获取当前WiFi SSID(保持不变)
|
||
if platform == "android":
|
||
from jnius import autoclass
|
||
PythonActivity = autoclass('org.kivy.android.PythonActivity')
|
||
Context = autoclass('android.content.Context')
|
||
activity = PythonActivity.mActivity
|
||
wifi_service = activity.getSystemService(Context.WIFI_SERVICE)
|
||
wifi_info = wifi_service.getConnectionInfo()
|
||
current_wifi_id = wifi_info.getSSID().strip('"').lower()
|
||
else:
|
||
current_wifi_id = "zhizhan-2"
|
||
|
||
# 读取CSV配置(保持不变)
|
||
with open("data/Users.csv", "r", encoding="utf-8") as file:
|
||
csv_reader = csv.DictReader(file)
|
||
for row in csv_reader:
|
||
csv_ssid = row['Wifi_SSID'].strip().lower()
|
||
if current_wifi_id == csv_ssid:
|
||
modbus_ip = row['Modbus_IP']
|
||
modbus_port = int(row['Modbus_Port']) if row['Modbus_Port'] else 502
|
||
break
|
||
|
||
if not modbus_ip:
|
||
Clock.schedule_once(lambda dt: self.dialog1("未找到匹配的Modbus配置"))
|
||
return
|
||
|
||
# 断开现有连接(保持不变)
|
||
self.modbus_master.disconnect()
|
||
|
||
# 创建新连接并测试(保持不变)
|
||
connect_result = self.modbus_master.connect(modbus_ip, modbus_port)
|
||
if not connect_result['success']:
|
||
Clock.schedule_once(lambda dt: self.dialog1(connect_result['msg']))
|
||
return
|
||
print(f"Modbus连接成功 (modbus-tk)\nIP: {modbus_ip}\n端口: {modbus_port}")
|
||
Clock.schedule_once(lambda dt: self.dialog1(f"Modbus连接成功\nIP: {modbus_ip}\n端口: {modbus_port}"))
|
||
|
||
except FileNotFoundError as e:
|
||
# 修复:将异常信息转为字符串或通过默认参数传递
|
||
err_msg = "配置文件 Users.csv 未找到"
|
||
Clock.schedule_once(lambda dt, msg=err_msg: self.dialog1(msg))
|
||
except modbus_tk.modbus.ModbusError as e:
|
||
# 修复:使用默认参数传递异常信息
|
||
err_msg = f"Modbus协议错误: {e}\n从站地址: {e.slave}\n功能码: {e.function_code}"
|
||
Clock.schedule_once(lambda dt, msg=err_msg: self.dialog1(msg))
|
||
self.modbus_master = None
|
||
except socket.error as e:
|
||
# 修复:提前格式化错误信息
|
||
err_msg = f"网络连接失败: {e}"
|
||
Clock.schedule_once(lambda dt, msg=err_msg: self.dialog1(msg))
|
||
self.modbus_master = None
|
||
except Exception as e:
|
||
# 修复:捕获所有其他异常
|
||
err_msg = f"连接失败: {str(e)}"
|
||
Clock.schedule_once(lambda dt, msg=err_msg: self.dialog1(msg))
|
||
self.modbus_master = None
|
||
|
||
threading.Thread(target=_connect_in_background, daemon=True).start()
|
||
|
||
###############################################SIGNUP Page Functions#####################################################
|
||
|
||
# signup Verification function "check_signup"
|
||
# def check_signup(self, name, prn, email, num, password, branch, sem, Wifi_SSID, modbus_ip, modbus_port):
|
||
# if name == "" or prn == "" or email == "" or num == "" or password == "" or branch == "" or sem == "":
|
||
# check = "Enter all required fields"
|
||
# return self.dialog1(check)
|
||
# else:
|
||
# status = "None"
|
||
# with open('data/Users.csv', "r") as file:
|
||
# csv_reader = csv.reader(file, delimiter=',')
|
||
# for line in csv_reader:
|
||
# try:
|
||
# if line[3] == num:
|
||
# status = "num"
|
||
# break
|
||
# if line[1] == prn:
|
||
# status = "prn"
|
||
# break
|
||
# if line[2] == email:
|
||
# status = "email"
|
||
# break
|
||
# else:
|
||
# status = False
|
||
# except IndexError:
|
||
# pass
|
||
# if status == "num":
|
||
# check = "Number already registered Please enter a new number"
|
||
# return self.dialog1(check)
|
||
# elif status == "prn":
|
||
# check = "PRN already registered Please enter a PRN"
|
||
# return self.dialog1(check)
|
||
# elif status == "email":
|
||
# check = "Email already registered Please enter a new email"
|
||
# return self.dialog1(check)
|
||
# else:
|
||
# self.root.current = "otp"
|
||
# self.send_otp(num)
|
||
# # 保存注册信息时包含Modbus信息
|
||
# self.signup_modbus_ip = modbus_ip
|
||
# self.signup_modbus_port = modbus_port
|
||
# check = "One Time Password has been shared on your registered Whatsapp No. Successful!."
|
||
# self.dialog1(check)
|
||
|
||
##################################################FORGOT PassWord Page##################################################
|
||
|
||
# # FORGOT PASSWORD page mobile number verification function 'verify_no'
|
||
# def verify_no(self):
|
||
# status = False
|
||
# if self.mobile_no.text == "":
|
||
# check = "Please enter your Mobile Number."
|
||
# return self.dialog1(check)
|
||
# else:
|
||
# with open('data/Users.csv', "r", encoding="utf-8") as file:
|
||
# csv_reader = csv.reader(file, delimiter=",")
|
||
# for line in csv_reader:
|
||
# try:
|
||
# if line[3] == self.mobile_no.text:
|
||
# status = True
|
||
# break
|
||
# else:
|
||
# status = False
|
||
# except IndexError:
|
||
# pass
|
||
# except Exception as e:
|
||
# print(e)
|
||
|
||
# if status:
|
||
# check = "One Time Password has been shared on your registered Whatsapp No. Successful!."
|
||
# self.root.current = "otp"
|
||
# self.send_otp(self.mobile_no.text)
|
||
# return self.dialog1(check)
|
||
# else:
|
||
# check = "Enter Registered Mobile Number."
|
||
# self.dialog1(check)
|
||
|
||
# def reset_password(self):
|
||
# if self.new_pass.text == "" or self.new_pass1.text == "":
|
||
# check = "Please enter your new password"
|
||
# return self.dialog1(check)
|
||
|
||
# elif not self.new_pass.text == self.new_pass1.text:
|
||
# check = "Password Does Not Match. \nPlease Re-check your password."
|
||
# return self.dialog1(check)
|
||
|
||
# else:
|
||
# with open('data/Users.csv', "r", encoding="utf-8") as file:
|
||
# csv_reader = csv.DictReader(file, delimiter=",")
|
||
# rows = [row for row in csv_reader]
|
||
|
||
# for row in rows:
|
||
# if row['Reserve'] == self.mobile_no.text:
|
||
# row['User_pass'] = self.new_pass.text
|
||
# break
|
||
|
||
# try:
|
||
# with open('data/Users.csv', "w", newline='', encoding="utf-8") as file:
|
||
# headers = ["User", "Reserve", "Student_Email", "Reserve", "User_pass",
|
||
# "Branch", "Semester"]
|
||
# csv_writer = csv.DictWriter(file, fieldnames=headers)
|
||
# csv_writer.writeheader()
|
||
# csv_writer.writerows(rows)
|
||
# check = "Password Updated Successfully!"
|
||
# self.root.current = "login"
|
||
# except Exception as e:
|
||
# print(e)
|
||
# check = "Something went wrong please try again."
|
||
# self.dialog1(check)
|
||
|
||
###############################################PROFILE & EDIT Profile Page##############################################
|
||
|
||
def edit_profile(self):
|
||
if self.edit_name.text == "" or self.edit_prn.text == "" or self.edit_email.text == "" or self.edit_number.text == "":
|
||
check = "Enter all required fields"
|
||
return self.dialog1(check)
|
||
else:
|
||
with open('data/Users.csv', "r", encoding="utf-8") as file:
|
||
csv_reader = csv.DictReader(file, delimiter=",")
|
||
rows = [row for row in csv_reader]
|
||
|
||
for row in rows:
|
||
if row['Wifi_SSID'] == self.profile_wifi_ssid.text:
|
||
row['User'] = self.edit_name.text
|
||
row['User_pass'] = self.edit_prn.text
|
||
row['Wifi_SSID'] = self.edit_email.text
|
||
row['Modbus_IP'] = self.edit_number.text
|
||
row['Modbus_Port'] = self.password.text
|
||
row['Reserve'] = self.edit_branch.text
|
||
row['Reserve'] = self.edit_semester.text
|
||
break
|
||
|
||
with open('data/Users.csv', newline="", mode="w", encoding="utf-8") as file:
|
||
header = ["User", "User_pass", "Wifi_SSID", "Modbus_IP", "Modbus_Port",
|
||
"Reserve", "Reserve"]
|
||
csv_writer = csv.DictWriter(file, fieldnames=header)
|
||
csv_writer.writeheader()
|
||
csv_writer.writerows(rows)
|
||
self.verify(True)
|
||
self.root.current = "home"
|
||
|
||
def secure_profile(self):
|
||
self.profile_edit_screen.ids.edit_email.readonly = True
|
||
self.profile_edit_screen.ids.edit_prn.readonly = True
|
||
self.profile_edit_screen.ids.edit_no.readonly = True
|
||
self.profile_edit_screen.ids.edit_private_credential_butn.disabled = False
|
||
|
||
if __name__ == '__main__':
|
||
app().run()
|
||
|
||
|
||
|