diff --git a/1.py b/1.py deleted file mode 100644 index fa756f5..0000000 --- a/1.py +++ /dev/null @@ -1,2 +0,0 @@ -from kivy.properties import ObjectProperty, StringProperty -# print("ok") \ No newline at end of file diff --git a/comm_device.py b/comm_device.py deleted file mode 100644 index e460beb..0000000 --- a/comm_device.py +++ /dev/null @@ -1,99 +0,0 @@ -import struct -from comm_protocol import class_protocol - -DEFAULT_COMM_WRITE_TIMEOUT_MS = 500 - -#通讯设备基类, 派生类需要实现 device_comm_cycle函数, read_register函数, write_registers函数 -class class_comm_device() : - def __init__(self, - comm_addr = 0, - device_remap = None, - unique_name = None, - protocol : class_protocol = None) : - - self.comm_active = True - self.comm_addr = comm_addr - self.device_remap = device_remap - self.uniqut_name = unique_name - self.protocol = protocol - - #该函数为虚基类, 本身未实现read_register, 以下为实现范例, 需要在派生类中实现 - def read_register(self, reg_addr, reg_count) : - raise NotImplementedError() - - #bool write_registers(int reg_addr, reg_count, uint16_t value[]) - #该函数为虚基类, 本身未实现write_registers, 以下为实现范例, 需要在派生类中实现 - def write_register(self, reg_addr, reg_count, new_value, timeout_ms = DEFAULT_COMM_WRITE_TIMEOUT_MS) : - raise NotImplementedError() - - #bool write_bit_register(int reg_addr, uint16_t value[]) - #bool write_bit_register(int reg_addr, uint16_t value) - def write_bit_register(self, reg_addr, value, timeout_ms = DEFAULT_COMM_WRITE_TIMEOUT_MS) : - raise NotImplementedError() - - def device_comm_cycle(self) : - comm_success_count = 0 - total_comm_count = 0 - return comm_success_count, total_comm_count - - def device_comm_flush_request(self, reg_addr, reg_count, cycle = 3000) : - return True - - def device_comm_deactive(self) : - self.comm_active = False - - def device_comm_active(self) : - self.comm_active = True - - - def value_u16_to_s16(self, value) : - if value == None: - return None - svalue = value - if (svalue & 0x8000) : - svalue = -((svalue ^ 0xFFFF) + 1) - return svalue - - def value_u32_to_s32(self, value) : - if value == None: - return None - svalue = value - if (svalue & 0x80000000) : - svalue = -((svalue ^ 0xFFFFFFFF) + 1) - return svalue - - def read_register_count(self, reg_addr, reg_count) : - return self.read_register(reg_addr, reg_count) - - def read_register_u16(self, reg_addr) : - result = self.read_register_count(reg_addr, 1) - if result : - result = (result[0] & 0xFFFF) - return result - - def read_register_s16(self, reg_addr) : - result = self.read_register_u16(reg_addr) - sign_result = self.value_u16_to_s16(result) - return sign_result - - def read_register_u32(self, reg_addr, big_endian = 0) : - result = self.read_register_count(reg_addr, 2) - if result : - if big_endian: - result = (result[1] & 0xFFFF) | ((result[0] & 0xFFFF) << 16) - else : - result = (result[0] & 0xFFFF) | ((result[1] & 0xFFFF) << 16) - return result - - def read_register_s32(self, reg_addr, big_endian = 0) : - result = self.read_register_u32(reg_addr, big_endian) - sign_value = self.value_u32_to_s32(result) - return sign_value - - def read_register_f32(self, reg_addr, big_endian = 0) : - result = self.read_register_u32(reg_addr, big_endian) - fvalue = None - if result : - bytes = struct.pack('BBBB', result & 0xFF, (result >> 8) & 0xFF, (result >> 16) & 0xFF, (result >> 24) & 0xFF) - fvalue = struct.unpack("= reg_addr_begin and reg_addr + reg_count <= reg_addr_end : - return True - return False - - def update_item_value(self, reg_addr, reg_count, new_value) : - if self.in_range(reg_addr, reg_count) and len(self.reg_buf) : - reg_off = reg_addr - self.reg_addr - new_reg = list(self.reg_buf) - for i in range(reg_count) : - new_reg[reg_off + i] = new_value[i] - self.reg_buf = new_reg - self.comm_trigger = True - - def read_register_count(self, reg_addr, reg_count) : - reg_addr_begin = self.reg_addr - reg_addr_end = self.reg_addr + self.reg_count - result = None - if reg_addr >= reg_addr_begin and reg_addr + reg_count <= reg_addr_end : - if len(self.reg_buf) >= self.reg_count: - result = [] - reg_off = reg_addr - self.reg_addr - for i in range(reg_count): - result.append(self.reg_buf[reg_off + i]) - - return result - -#为了防止阻塞 mqtt订阅流程, 采用class_mqtt_process_thread线程来处理 接收到的主题与消息 -class class_mqtt_process_thread(Thread): - def __init__(self, - parent_device, - topic : str = None, - message : str = None, - ): - - Thread.__init__(self) - self.topic = topic - self.message = message - self.parent_device : class_modbus_comm_device = parent_device - - def run(self): - self.parent_device.on_process_topic_message(self.topic, self.message) - -#modbus通讯设备, 管理modbus主机通讯, 实现mqtt客户端 -class class_modbus_comm_device(class_comm_device, class_comm_mqtt_interface) : - def __init__(self, - comm_addr = 0, - device_remap = None, - comm_table = None, - func_comm_trigger = None, - mqtt_thread : class_comm_mqtt_thread = None, - protocol : class_protocol_modbus = None, - mqtt_info_object : class_mqtt_info_object = None, - unique_name = None, - action_process_func = None, #action处理函数 - request_alarm_func = None, #故障查询函数 - alias_table = None): - class_comm_device.__init__(self, comm_addr, device_remap, unique_name) - class_comm_mqtt_interface.__init__(self) - - self.comm_loop_count = 0 - self.comm_index = 0 - self.mqtt_thread = mqtt_thread - self.comm_device_comm_active = True #设置该设备是否需要通讯 - self.comm_fail_delay = 0 #通讯延时 - self.func_comm_trigger = func_comm_trigger - self.protocol : class_protocol_modbus = protocol - self.mqtt_info_object : class_mqtt_info_object = mqtt_info_object - self.unique_name : str = unique_name - self.action_process_func = action_process_func - self.request_alarm_func = request_alarm_func - self.alias_table = alias_table - - self.comm_table = comm_table - self.comm_table_item_list : class_comm_table_item = [] #list of class_comm_table_item - self.create_comm_item_list(comm_table) - - def modbus_regs_flush(self, reg_addr, reg_count, values) : - for each in self.comm_table_item_list: - comm_item : class_comm_table_item = each - comm_item.update_item_value(reg_addr, reg_count, values) - - def create_comm_item_list(self, comm_table : class_comm_table_item) : - self.comm_table_item_list = [] - if comm_table != None : - for comm_item_dict in comm_table : - _name = utils.dict_or_object_get_attr(comm_item_dict, "name", " ") - _reg_addr = utils.dict_or_object_get_attr(comm_item_dict, "reg_addr", 0) - _reg_count = utils.dict_or_object_get_attr(comm_item_dict, "reg_count", 0) - _cycle = utils.dict_or_object_get_attr(comm_item_dict, "cycle", 0) - _mqtt_pack = utils.dict_or_object_get_attr(comm_item_dict, "mqtt_pack", None) - self.comm_table_item_list.append(class_comm_table_item(name = _name, - reg_addr =_reg_addr, - reg_count = _reg_count, - cycle = _cycle, - mqtt_pack = _mqtt_pack)) - - #@override, mqtt on connect - def on_connect(self, mqtt_thread, userdata, flags, rc) : - if rc == 0 : - #获取线程类 (class_comm_mqtt_thread) - mqtt_comm_thread : class_comm_mqtt_thread= mqtt_thread - #订阅相关主题, 获取参数, 修改参数, 获取测量值, 获取报警信息 - mqtt_comm_thread.subscribe("request/param/info/#") - mqtt_comm_thread.subscribe("request/param/modify/#") - mqtt_comm_thread.subscribe("request/measure/#") - mqtt_comm_thread.subscribe("request/status/#") - mqtt_comm_thread.subscribe("request/alarm/#") - mqtt_comm_thread.subscribe("request/action/#") - mqtt_comm_thread.subscribe("request/alias/#") - - def alias_table_convert(self) : - new_list_dict = [] - - for each_dict in self.alias_table : - for key_info, value_dict in each_dict.items() : - if isinstance(key_info, Enum) : - name = key_info.name - else : - name = key_info - - new_dict = {} - for dict_key, dict_value in value_dict.items() : - if isinstance(dict_key, Enum) : - dict_key_value = dict_key.value[0] - else : - dict_key_value = dict_key - - new_dict[dict_key_value] = dict_value - - new_list_dict.append({name : new_dict}) - - return new_list_dict - - #该函数在线程里面调用, 不会阻塞mqtt处理订阅的消息 - def on_process_topic_message(self, topic, message) : - try : - if isinstance(message, bytes) : - json_dict = json.loads(message.decode('utf-8')) - else : - json_dict = json.loads(message.encode('utf-8')) - print_normal_msg(f"有效的mqtt(topic = {topic}, message = {message})") - except Exception as e: - print_error_msg(f"{str(e)}无效的mqtt(topic = {topic}, message = {message})") - json_dict = None - - mqtt_info_name = utils.dict_or_object_get_attr(json_dict, "name", None) - value_str = utils.dict_or_object_get_attr(json_dict, "value", math.nan) - - - # if mqtt_info_name != None : - # mqtt_menu_item = self.mqtt_info_object.search_menu_item(mqtt_info_name) - # else : - # mqtt_menu_item = None - if mqtt_info_name != None: - mqtt_menu_item = self.mqtt_info_object.search_menu_item(mqtt_info_name) - else : - mqtt_menu_item = None - print_normal_msg(f"执行操作: topic={topic}, mqtt_info_name={mqtt_info_name}") - - if "request/alias" in topic : #获取别名 - new_alias_table = self.alias_table_convert() - if mqtt_info_name == None : - msg : str = json.dumps(new_alias_table, ensure_ascii=False) - if self.mqtt_thread != None : - self.mqtt_thread.publish("response/alias/" + self.unique_name, msg) - else : - search_dict = None - for each_dict in new_alias_table : - if mqtt_info_name in each_dict.keys() : - search_dict = each_dict - break - if search_dict : - msg : str = json.dumps(search_dict, ensure_ascii=False) - else : - msg : str = '{"%s" : None}'%(mqtt_info_name) - if self.mqtt_thread != None : - self.mqtt_thread.publish("response/alias/" + self.unique_name, msg) - elif "request/alarm" in topic: #故障查询 - if self.request_alarm_func != None: - fvalue = utils.dict_or_object_get_attr(json_dict, "index", math.nan) - if isinstance(fvalue, str) : - fvalue = float(fvalue) - if fvalue != math.nan : - alarm_index = round(fvalue) - self.request_alarm_func(self, alarm_index) - elif "request/action" in topic : - if self.action_process_func : - self.action_process_func(self, mqtt_menu_item, value_str) - - elif "request/param/info" in topic: #读取参数 - _scale = utils.dict_or_object_get_attr(mqtt_menu_item, "scale", 1.0) - _offset = utils.dict_or_object_get_attr(mqtt_menu_item, "offset", 0.0) - _comm_str = utils.dict_or_object_get_attr(mqtt_menu_item, "addr", None) - _alias_name = utils.dict_or_object_get_attr(mqtt_menu_item, "alias", None) - if isinstance(_alias_name, Enum): - _alias_name = _alias_name.name - - _format = utils.dict_or_object_get_attr(mqtt_menu_item, "format", "%f") - _fvalue = math.nan - - if _comm_str : - _fvalue = self.protocol.read_float(device_addr = self.comm_addr, - comm_str = _comm_str, - scale = _scale, - offset = _offset - ) - # if _alias_name != None : - # # if _fvalue == None or _fvalue == math.nan: - # # _format_str = "NAN" - # if _fvalue is None or math.isnan(_fvalue): - # _fvalue = 0 - # else : - # _format_str = "%d"%(round(_fvalue)) - # if self.mqtt_thread != None : - # self.mqtt_thread.publish("response/param/info/" + self.unique_name, '{"%s" : {"alias" : "%s", "value": "%s"}}'%(mqtt_info_name, _alias_name, _format_str)) - # else : - # _format_str = _format%(_fvalue) - # if self.mqtt_thread != None : - # self.mqtt_thread.publish("response/param/info/" + self.unique_name, '{"%s" : "%s"}'%(mqtt_info_name, _format_str)) - # else: - # print_warning_msg(f"未处理的请求:{topic, json_dict}") - if _alias_name is not None: - # 处理 _fvalue 的情况 - if _fvalue is None or math.isnan(_fvalue): - _fvalue = 0 - _format_str = "%d" % (round(_fvalue)) - else: - # 当 _alias_name 为 None 时处理 - _format_str = _format % (_fvalue) if _fvalue is not None and not math.isnan(_fvalue) else "UNKNOWN" - - # 发布消息 - if self.mqtt_thread is not None: - if _alias_name is not None: - self.mqtt_thread.publish("response/param/info/" + self.unique_name, - '{"%s" : {"alias" : "%s", "value": "%s"}}' % (mqtt_info_name, _alias_name, _format_str)) - else: - self.mqtt_thread.publish("response/param/info/" + self.unique_name, - '{"%s" : "%s"}' % (mqtt_info_name, _format_str)) - else: - print_warning_msg(f"未处理的请求:{topic, message}") - - - - elif "request/param/modify" in topic : #写入参数 - - mqtt_menu_item = self.comm_item_item_adjust(mqtt_menu_item) - scale = utils.dict_or_object_get_attr(mqtt_menu_item, "scale", 1.0) - format_str = utils.dict_or_object_get_attr(mqtt_menu_item, "format", "%1.0f") - offset = utils.dict_or_object_get_attr(mqtt_menu_item, "offset", 0.0) - _comm_str = utils.dict_or_object_get_attr(mqtt_menu_item, "addr", None) - - _fvalue = value_str - if isinstance(_fvalue, str) : - modify_fvalue = float(_fvalue) - else : - modify_fvalue = _fvalue - - _fvalue_origin = modify_fvalue / scale - offset - if _comm_str : - result = self.protocol.write_float(device_addr = self.comm_addr, - comm_str = _comm_str, - fvalue = _fvalue_origin) - if self.mqtt_thread != None : - self.mqtt_thread.publish("response/param/modify/" + self.unique_name, '{"name" : "%s", "result":%d}'%(mqtt_info_name, result)) - else: - print_warning_msg(f"未处理的请求:{topic, json_dict}") - elif mqtt_menu_item == None : - print_warning_msg(f"mqtt无法找到对应信息项(topic = {topic}, message = {json_dict})") - else : - pass - - #@override, mqtt subscirbe message process - def on_message(self, mqtt_thread, topic, message) : - if self.mqtt_info_object == None : - return False - if "request/alias" in topic : #获得别名不需要协议通讯, 此处直接处理即可 - self.on_process_topic_message(topic, message) - elif "request" in topic : - new_thread : class_mqtt_process_thread = class_mqtt_process_thread(self, topic, message) - new_thread.start() - return True - - #通过通讯字符串与scale类型, 获取浮点格式实际值, 通讯失败时返回None - def comm_item_get_value_float(self, comm_addr_str, scale = 1.0, offset = 0) : - reg_value = None - - if comm_addr_str != None: - reg_addr, bit, reg_count = utils.comm_str_unpack(comm_addr_str) - is_float = True if "#f" in comm_addr_str else False - is_big_endian = True if "#>" in comm_addr_str else False - is_sign = True if "#s" in comm_addr_str else False - - if reg_count == 1 : - if is_sign : - reg_value = self.read_register_s16(reg_addr) - else : - reg_value = self.read_register_u16(reg_addr) - if reg_count == 2 : - if is_float : - reg_value = self.read_register_f32(reg_addr, is_big_endian) - elif is_sign : - reg_value = self.read_register_s32(reg_addr, is_big_endian) - else : - reg_value = self.read_register_u32(reg_addr, is_big_endian) - - if bit >= 0 and reg_value != None: - reg_value = (reg_value >> bit) - reg_value = reg_value & (0xFFFFFFFF >> (32 - reg_count)) - - if reg_value != None : - reg_value = reg_value * scale + offset - - return reg_value - - #有些菜单项的scale, format或其他属性可以动态调节, 返回调整后的菜单项或 原菜单项 - def comm_item_item_adjust(self, menu_item) : - adjust_menu_item = None - func_item_adjust = utils.dict_or_object_get_attr(menu_item, "adjust", None) - if func_item_adjust != None : - adjust_menu_item = func_item_adjust(self, menu_item) - if adjust_menu_item == None : - adjust_menu_item = menu_item - return adjust_menu_item - - #通过菜单项中 特定的回调函数, 使每个菜单项可以独立处理一些任务, 比如添加自定义key, value - def comm_call_menu_item_func(self, menu_item_dict, mqtt_dict : dict = None) : - call_func = utils.dict_or_object_get_attr(menu_item_dict, "call", None) - if call_func != None : - call_func(self, menu_item_dict, mqtt_dict) - - #通过菜单项中 获取浮点格式实际值, reg_value在通讯失败时返回None, 需要额外检查 - def comm_get_value_from_menu_item(self, menu_item_dict) : - menu_item_dict = self.comm_item_item_adjust(menu_item_dict) - scale = utils.dict_or_object_get_attr(menu_item_dict, "scale", 1.0) - offset = utils.dict_or_object_get_attr(menu_item_dict, "offset", 0.0) - comm_addr_str = utils.dict_or_object_get_attr(menu_item_dict, "addr", None) - reg_value = self.comm_item_get_value_float(comm_addr_str, scale, offset) - return reg_value - - #通过mqtt名称中 获取浮点格式实际值, reg_value在通讯失败时返回None, 需要额外检查 - def comm_get_value_from_mqtt_name(self, mqtt_name : str) : - if mqtt_name in self.mqtt_info_object.mqtt_dict.keys() : - mqtt_menu_item = self.mqtt_info_object.mqtt_dict[mqtt_name] - return self.comm_get_value_from_menu_item(mqtt_menu_item) - return None - - #触发一组mqtt菜单组的 key, value字典 - def comm_item_trigger_mqtt_pack(self, mqtt_pack) : - if mqtt_pack == None : - return None - mqtt_dict = {} - for pack_item_dict in mqtt_pack : - self.comm_call_menu_item_func(pack_item_dict, mqtt_dict) - reg_value = self.comm_get_value_from_menu_item(pack_item_dict) - format_str = utils.dict_or_object_get_attr(pack_item_dict, "format", "%1.0f") - mqtt_name = utils.dict_or_object_get_attr(pack_item_dict, "mqtt", None) - min_value = utils.dict_or_object_get_attr(pack_item_dict, "min", None) - max_value = utils.dict_or_object_get_attr(pack_item_dict, "max", None) - - # 检查是否有最小值和最大值的约束,并验证 reg_value 是否在范围内 - if reg_value is not None: - if min_value is not None and reg_value < min_value: - reg_value = min_value # 如果小于最小值,设为最小值 - if max_value is not None and reg_value > max_value: - reg_value = max_value # 如果大于最大值,设为最大值 - - if mqtt_name != None and reg_value != None: - mqtt_dict[mqtt_name] = format_str%(reg_value) - return mqtt_dict - - def trigger_comm(self, name): - for item in self.comm_table_item_list: - comm_table_item : class_comm_table_item = item - if comm_table_item.name == name : - comm_table_item.comm_trigger = True - return - - def read_register_count(self, reg_addr, reg_count) : - result = None - for item in self.comm_table_item_list : - comm_table_item : class_comm_table_item = item - - if comm_table_item.in_range(reg_addr, reg_count) : - if comm_table_item.reg_buf == None : - comm_table_item.comm_trigger = True - elif len(comm_table_item.reg_buf) == 0 : - comm_table_item.comm_trigger = True - else : - result = comm_table_item.read_register_count(reg_addr, reg_count) - if result != None : - break - return result - - #@device_comm_flush_request override - def device_comm_flush_request(self, reg_addr, reg_count, cycle = 3000) : - for item in self.comm_table_item_list : - comm_table_item : class_comm_table_item = item - if comm_table_item.in_range(reg_addr, reg_count) : - if comm_table_item.flush_request_delay == 0 : - comm_table_item.flush_request_delay = cycle - - #@read_register override - def read_register(self, comm_str) : - reg_addr, bit, reg_count = utils.comm_str_unpack(comm_str) - if reg_count == 0: - return None - return self.read_register_count(reg_addr, reg_count) - - #@read_register override - #bool write_register(int reg_addr, reg_count, uint16_t value[]) - def write_register(self, reg_addr, reg_count, new_value, timeout_ms = comm_device.DEFAULT_COMM_WRITE_TIMEOUT_MS) : - try: - _protocol : class_protocol_modbus = self.protocol - - _old_timeout = _protocol.get_timeout() - _protocol.set_timeout(timeout_ms / BASE_FAIL_DELAY) - - write_result = _protocol.modbus_write_regs(self.comm_addr, - reg_addr, - reg_count, - new_value, - ) - - if write_result == True: - for item in self.comm_table_item_list : - comm_item : class_comm_table_item = item - if comm_item.in_range(reg_addr, reg_count) : - comm_item.update_item_value(reg_addr, reg_count, new_value) - - except Exception : - write_result = False - finally : - _protocol.set_timeout(_old_timeout) - - return write_result - - #bool write_bit_register(int reg_addr, uint16_t value[]) - #bool write_bit_register(int reg_addr, uint16_t value) - def write_bit_register(self, reg_addr, value, timeout_ms = comm_device.DEFAULT_COMM_WRITE_TIMEOUT_MS) : - write_result = False - - _protocol : class_protocol_modbus = self.protocol - try : - old_timeout = _protocol.get_timeout() - _protocol.set_timeout(timeout_ms / BASE_FAIL_DELAY) - _protocol.modbus_write_regs(self.comm_addr, - reg_addr % 100000 + 100000, - len(value), - value) - - write_result = True - except Exception as e: - write_result = False - print_error_msg(f"modbus寄存器无法写入{str(e)}") - finally : - _protocol.set_timeout(old_timeout) - - return write_result - - #@override cycle function - def update_time_difference(self, table_item): - cur_time = time.time() # 获取当前时间 - time_dif = cur_time - table_item.base_time # 计算时间差 - table_item.base_time = cur_time # 更新基准时间 - return time_dif * BASE_FAIL_DELAY # 返回时间差(毫秒) - - def should_trigger_comm(self, table_item, time_dif_ms): - comm_trigger = False # 初始化通信触发标志为False - if self.func_comm_trigger: - comm_trigger = self.func_comm_trigger(self, table_item) # 调用通信触发函数 - - if table_item.remain_cycle > time_dif_ms: - table_item.remain_cycle -= time_dif_ms # 减少剩余周期 - else: - table_item.remain_cycle = table_item.cycle + table_item.comm_fail_delay + self.comm_fail_delay # 重新计算剩余周期 - if table_item.cycle > 0 or (table_item.cycle == 0 and not table_item.comm_success): - comm_trigger = True # 如果周期大于0或周期为0但上次通信不成功,则触发通信 - - if table_item.flush_request_delay > 0: - if table_item.flush_request_delay > time_dif_ms: - table_item.flush_request_delay -= time_dif_ms # 减少刷新请求延迟 - else: - table_item.flush_request_delay = 0 # 重置刷新请求延迟 - comm_trigger = True # 触发通信 - - if not comm_trigger: - comm_trigger = table_item.comm_trigger # 如果前面没有触发通信,则使用通信触发标志 - - return comm_trigger # 返回是否触发通信 - - def execute_communication(self, table_item): - read_result = [] # 初始化读取结果 - timeout_ms = getattr(table_item, "通信超时", DEFAULT_TIMEOUT) # 获取超时时间,默认500ms - _protocol = self.protocol # 获取协议对象 - - try: - old_timeout = _protocol.get_timeout() # 保存旧的超时时间 - _protocol.set_timeout(timeout_ms / BASE_FAIL_DELAY) # 设置新的超时时间 - - read_result = _protocol.modbus_read_regs(self.comm_addr, table_item.reg_addr, table_item.reg_count) # 执行Modbus读取 - if len(read_result) != table_item.reg_count: - read_result = [] # 如果读取结果数量不匹配,视为读取失败 - except Exception as e: - print_error_msg("周期读异常: ", e, f"modbus_read_regs(addr={self.comm_addr}, reg={table_item.reg_addr}, count={table_item.reg_count})") # 打印错误信息 - finally: - _protocol.set_timeout(old_timeout) # 恢复旧的超时时间 - - return read_result # 返回读取结果 - - def handle_comm_result(self, table_item, read_result): - if not read_result: # 如果读取结果为空,表示通信失败 - self.handle_comm_failure(table_item) - else: # 否则通信成功 - self.handle_comm_success(table_item, read_result) - - table_item.comm_trigger = False # 重置通信触发标志 - - def handle_comm_failure(self, table_item): - table_item.comm_fail_count += 1 # 增加通信失败计数 - table_item.comm_fail_delay = self.limit_delay(table_item.comm_fail_delay + BASE_FAIL_DELAY, MAX_FAIL_DELAY) # 增加并限制通信失败延迟 - self.comm_fail_delay = self.limit_delay(self.comm_fail_delay + BASE_GLOBAL_FAIL_DELAY, 60000) # 增加并限制全局通信失败延迟 - table_item.comm_success = False # 标记通信失败 - - def limit_delay(self, delay, max_delay): - """限制延迟不超过最大值""" - return min(delay, max_delay) - - - - def handle_comm_success(self, table_item, read_result): - table_item.comm_fail_delay = 0 # 重置通信失败延迟 - self.comm_fail_delay = 0 # 重置全局通信失败延迟 - table_item.reg_buf = read_result # 更新寄存器缓存 - table_item.comm_success = True # 标记通信成功 - table_item.comm_success_count += 1 # 增加成功计数 - - if table_item.mqtt_pack: - self.publish_mqtt_message(table_item) # 发布MQTT消息 - - def publish_mqtt_message(self, table_item): - json_topic = f"{table_item.name}/{self.unique_name}" # 构建MQTT主题 - msg_dict = self.comm_item_trigger_mqtt_pack(table_item.mqtt_pack) # 触发MQTT打包 - - if msg_dict: - json_message = json.dumps(msg_dict, ensure_ascii=False) # 序列化消息字典 - if self.mqtt_thread: - self.mqtt_thread.publish(json_topic, json_message) # 发布MQTT消息 - - - def device_comm_cycle(self): - comm_success_count = 0 # 初始化成功计数 - total_comm_count = 0 # 初始化总计数 - - if self.comm_table is None: - return comm_success_count, total_comm_count # 如果通信表为空,提前返回 - - for item in self.comm_table_item_list: - table_item = item # 获取表项 - if table_item.reg_count == 0: - continue # 如果寄存器计数为0,跳过此表项 - - time_dif_ms = self.update_time_difference(table_item) # 更新时间差 - comm_trigger = self.should_trigger_comm(table_item, time_dif_ms) # 检查是否应触发通信 - - if comm_trigger: - total_comm_count += 1 # 增加总通信计数 - read_result = self.execute_communication(table_item) # 执行通信 - - if read_result: - comm_success_count += 1 # 如果读取成功,增加成功计数 - - self.handle_comm_result(table_item, read_result) # 处理通信结果 - - return comm_success_count, total_comm_count # 返回成功计数和总计数 diff --git a/comm_protocol.py b/comm_protocol.py deleted file mode 100644 index e14c0a3..0000000 --- a/comm_protocol.py +++ /dev/null @@ -1,45 +0,0 @@ -import string -import modbus_tk.defines as cst -from modbus_tk import modbus_rtu, modbus_tcp, modbus -from print_color import * -import enum as Enum - -#所有协议基类 -class class_protocol() : - def __init__(self, protocol_name) : - self.protocol_name = protocol_name - self.mode : string = None - self.timeout = 5.0 - return - - def set_timeout(self, timeout = 5.0) : - self.timeout = timeout - - def open(self, mode : string) : - self.mode = mode - print_error_msg("class_protocol派生类未实现open函数") - raise NotImplementedError() - - def close(self) : - print_error_msg("class_protocol派生类未实现close函数") - raise NotImplementedError() - - #返回 math.nan 表示读取失败, 否则读取成功 - def read_float(self, device_addr : int, comm_str : string, scale : float = 1.0, offset : float = 0.0) -> float: - raise NotImplementedError() - - #返回 False 表示读取失败 - #返回 True 表示读取成功 - def write_float(self, device_addr : int, comm_str : string, fvalue : float, scale : float = 1.0, offset : float = 0.0) -> bool: - raise NotImplementedError() - - #读取comm_str地址开始的连续地址count个数, 地址连续 - #返回 math.nan 表示读取失败, 否则读取成功 - def read_float_arr(self, device_addr : int, comm_str : string, count : int) : - raise NotImplementedError() - - #写入comm_str地址开始的连续地址 写入总个数由 len(fvalue_arr)决定 - #返回 False 表示读取失败, 否则读取成功 - def write_float_arr(self, device_addr : int, comm_str : string, fvalue_arr : list) -> bool: - raise NotImplementedError() - \ No newline at end of file diff --git a/comm_protocol_modbus.py b/comm_protocol_modbus.py deleted file mode 100644 index 558097e..0000000 --- a/comm_protocol_modbus.py +++ /dev/null @@ -1,656 +0,0 @@ -#modbus协议处理 -import sys -import string -import json -import serial -import time -import menu_utils as utils -import string -import struct -import math -import modbus_tk.defines as cst -from modbus_tk import modbus_rtu, modbus_tcp, modbus -from print_color import * -from comm_protocol import class_protocol -from comm_thread import class_comm_master_thread -from threading import Thread, Lock -from modbus_tk.exceptions import( - ModbusError, ModbusFunctionNotSupportedError, DuplicatedKeyError, MissingKeyError, InvalidModbusBlockError, - InvalidArgumentError, OverlapModbusBlockError, OutOfModbusBlockError, ModbusInvalidResponseError, - ModbusInvalidRequestError -) - -def json_load_message(message) : - json_dict = {} - if isinstance(message, bytes) : - json_dict = json.loads(message.decode('utf-8')) - elif isinstance(message, str) : - json_dict = json.loads(message.encode('utf-8')) - return json_dict - -#从通讯字符串中取出寄存器地址,位地址,个数 -# 以下为允许的Modbus通讯地址信息 -#"8000#2" 从8000地址开始,连续取两个寄存器 -#"8000#2#s" 从8000地址开始,连续取两个寄存器, #s 代表有符号数, 缺省为无符号数 -#"8000" 或 "8000#1" 8000地址, 1个寄存器 -#"8000.2#3" 取8000地址的第2位开始取 3个位的数据 -#"8000#2#f#>" 8000地址开始,连续取两个寄存器, #> 大端模式, #f 浮点数, -#"8000#2#f" 或 "8000#2#f#<" 8000地址开始,连续取两个寄存器, #< 小端模式(缺省模式), #f 浮点数, 单精度 -#"8000#4#f" 或 "8000#4#f#<" 8000地址开始,连续取4个寄存器, #< 小端模式(缺省模式), #f 浮点数, 双精度 -#"100618" 位地址618, 超过100000就表示是位地址 -def get_modbus_comm_info(addr_string : string) : #tuple(int, int, int, bool, bool, bool) - reg_addr = 0 - reg_bit = -1 - reg_count = 0 - - is_sign = True if "#s" in addr_string else False - is_float = True if "#f" in addr_string else False - is_big_endian = True if "#>" in addr_string else False - - info_splits = addr_string.split("#") # 使用'#'作为分隔符 - if info_splits != None : - reg_bit_str : string = info_splits[0] - reg_bit_splits = reg_bit_str.split('.') - - if len(reg_bit_splits) == 2 : - reg_addr = int(reg_bit_splits[0]) - reg_bit = int(reg_bit_splits[1]) - else : - reg_addr = int(reg_bit_splits[0]) - reg_bit = -1 - - if len(info_splits) >= 2: - reg_count = int(info_splits[1]) - else : - reg_count = 1 - - return (reg_addr, reg_bit, reg_count, is_float, is_big_endian, is_sign) - -#modbus协议基类, 无法独立工作, 需要派生类实现对应函数 -class class_protocol_modbus(class_protocol) : - #protocol_port_name = "COM1", "dev/tty1" 之类的设备 - def __init__(self, protocol_name) : - class_protocol.__init__(self, protocol_name) - self.mode : string = None #协议open时的mode字符串 - self.master : modbus.Master = None #modbus主机 - self.last_errcode = 0 #协议最后一次故障代码 - self.timeout = 1.0 - self.mutex = Lock() - return - - def set_modbus_master(self, master : modbus.Master) : - if self.master != None : - self.master.close() - self.master = master - if self.master != None : - self.master.set_timeout(self.timeout) - - #reg_value最大为64位数据, reg_count最大为4 - def modbus_value_to_list(self, reg_value, reg_count, is_big_endian = False) -> list : - result = [] - if reg_count == 1 : - result.append(reg_value & 0xFFFF) - elif reg_count == 2: - if is_big_endian : - result.append((reg_value >> 16) & 0xFFFF) - result.append((reg_value >> 0) & 0xFFFF) - else : - result.append((reg_value >> 0) & 0xFFFF) - result.append((reg_value >> 16) & 0xFFFF) - elif reg_count == 3: - if is_big_endian : - result.append((reg_value >> 32) & 0xFFFF) - result.append((reg_value >> 16) & 0xFFFF) - result.append((reg_value >> 0) & 0xFFFF) - else : - result.append((reg_value >> 0) & 0xFFFF) - result.append((reg_value >> 16) & 0xFFFF) - result.append((reg_value >> 32) & 0xFFFF) - elif reg_count == 4: - if is_big_endian : - result.append((reg_value >> 48) & 0xFFFF) - result.append((reg_value >> 32) & 0xFFFF) - result.append((reg_value >> 16) & 0xFFFF) - result.append((reg_value >> 0) & 0xFFFF) - else : - result.append((reg_value >> 0) & 0xFFFF) - result.append((reg_value >> 16) & 0xFFFF) - result.append((reg_value >> 32) & 0xFFFF) - result.append((reg_value >> 48) & 0xFFFF) - - return result - - def modbus_list_to_value(self, read_regs : tuple, is_big_endian : bool = False) -> int: - read_reg_cunt = len(read_regs) - read_value = 0 - - if read_reg_cunt == 4 : - if is_big_endian : - read_value = (read_regs[0] << 48) | (read_regs[1] << 32) | (read_regs[2] << 16) | (read_regs[3] << 0) - else : - read_value = (read_regs[0] << 0) | (read_regs[1] << 16) | (read_regs[2] << 32) | (read_regs[3] << 48) - if read_reg_cunt == 3 : - if is_big_endian : - read_value = (read_regs[0] << 32) | (read_regs[1] << 16) | (read_regs[2] << 0) - else : - read_value = (read_regs[0] << 0) | (read_regs[1] << 16) | (read_regs[2] << 32) - elif read_reg_cunt == 2 : - if is_big_endian : - read_value = (read_regs[0] << 16) | (read_regs[1] << 0) - else : - read_value = (read_regs[0] << 0) | (read_regs[1] << 16) - elif read_reg_cunt == 1 : - read_value = read_regs[0] - - return read_value - - - - def modbus_read_regs(self, device_addr, reg_addr, reg_count) -> tuple: - result_tuple = [] - try: - self.mutex.acquire() - - if self.master is None: - raise Exception("Call set_modbus_master() first to init protocol master") - - read_reg_count = reg_count - is_bit_addr = reg_addr >= 100000 - func_code = cst.READ_COILS if is_bit_addr else cst.READ_HOLDING_REGISTERS - result_tuple = self.master.execute(slave=device_addr, - function_code=func_code, - starting_address=reg_addr % 100000, - quantity_of_x=read_reg_count) - except ModbusError as e: - self.last_errcode = e.get_exception_code() - err_msg = f"Modbus 读寄存器错误: {str(e)}, modbus 读寄存器(addr={device_addr}, reg={reg_addr}, count={reg_count})" - print_error_msg(err_msg) - raise - except Exception as e: - err_msg = f"其他错误: {str(e)}" - print_error_msg(err_msg) - raise - finally: - self.mutex.release() - - return result_tuple - - #reg_addr >= 100000 时为写 位地址, 否则写保持寄存器 - #values 传入整数或浮点数时, 表示写单个寄存器, 或 强制单个位, - #强制单个位时,modbus-tk会转化成0xFF00, 0x0000, 要是其他值时,需要修改modbus-tk底层库 - def modbus_write_regs(self, device_addr, reg_addr, reg_count, values) -> bool : - try : - success = False - - self.mutex.acquire() - - if self.master == None : - raise Exception("Call set_modbus_master() first to init protocol master") - - if isinstance(values, float) : - reg_value = (int)(round(values)) - values = [reg_value] - elif isinstance(values, int) : - reg_value = (int)(values) - values = [reg_value] - - if len(values) != reg_count or reg_count == 0: - raise Exception("error, value size %d not match to reg_count"%(len(values))) - - is_bit_addr = True if reg_addr >= 100000 else False - - if len(values) >= 2 : - func_code = cst.WRITE_MULTIPLE_COILS if is_bit_addr else cst.WRITE_MULTIPLE_REGISTERS - self.master.execute(slave = device_addr, - function_code = func_code, - starting_address = reg_addr % 100000, - quantity_of_x = len(values), - output_value= values) - else : - func_code = cst.WRITE_SINGLE_COIL if is_bit_addr else cst.WRITE_SINGLE_REGISTER - if func_code == cst.WRITE_SINGLE_COIL : - write_value= values[0] & 0xFFFF - else : - write_value = values[0] - - self.master.execute(slave = device_addr, - function_code = func_code, - starting_address = reg_addr % 100000, - quantity_of_x = len(values), - output_value= write_value) - success = True - except ModbusError as e: - self.last_errcode = e.get_exception_code() - print_error_msg(f"modbus写寄存器错误: {str(e)}, modbus写寄存器(addr={device_addr}, reg={reg_addr}, count={reg_count})") - success = False - except Exception as e: - success = False - print_error_msg(f"其他错误: {str(e)}") - finally: - self.mutex.release() - return success - - def modbus_read_float(self, device_addr, comm_str :string, scale = 1.0, offset = 0.0) -> float: - fvalue = math.nan - try : - reg_addr, reg_bit, reg_count, is_float, is_big_endian, is_sign = get_modbus_comm_info(comm_str) - if self.master == None : - raise Exception("Call set_modbus_master() first to init protocol master") - - read_reg_count = reg_count - if reg_bit >= 0 : - read_reg_count = 1 + (int)((reg_bit + reg_count - 1) / 16) - - result = self.modbus_read_regs(device_addr, reg_addr, read_reg_count) - - if read_reg_count == 4 : - if is_big_endian : - read_value = (result[0] << 48) | (result[1] << 32) | (result[2] << 16) | (result[3] << 0) - else : - read_value = (result[0] << 0) | (result[1] << 16) | (result[2] << 32) | (result[3] << 48) - if is_sign : - read_value = utils.value_u64_to_s64(read_value) - elif read_reg_count == 3 : - if is_big_endian : - read_value = (result[0] << 32) | (result[1] << 16) | (result[2] << 0) - else : - read_value = (result[0] << 0) | (result[1] << 16) | (result[2] << 32) - elif read_reg_count == 2 : - if is_big_endian : - read_value = (result[0] << 16) | (result[1] << 0) - else : - read_value = (result[0] << 0) | (result[1] << 16) - if is_sign : - read_value = utils.value_u32_to_s32(read_value) - elif read_reg_count == 1 : - read_value = result[0] - if is_sign : - read_value = utils.value_u16_to_s16(read_value) - else : - raise Exception("目前只支持读取(1,2,3,4)个寄存器个数") - - if reg_bit >= 0 : - read_value = (read_value >> reg_bit) & (0xFFFFFFFF >> (32 - reg_count)) - - if is_float : - fvalue = math.nan - if read_reg_count == 2: - bytes = struct.pack('BBBB', read_value & 0xFF, (read_value >> 8) & 0xFF, (read_value >> 16) & 0xFF, (read_value >> 24) & 0xFF) - fvalue = struct.unpack("> 8) & 0xFF, (low_part >> 16) & 0xFF, (low_part >> 24) & 0xFF) - high_part = (read_value >> 32) & 0xFFFFFFFF - high_bytes = struct.pack('BBBB', high_part & 0xFF, (high_part >> 8) & 0xFF, (high_part >> 16) & 0xFF, (high_part >> 24) & 0xFF) - bytes = low_bytes + high_bytes - fvalue = struct.unpack(" tuple(float) - fvalue = math.nan - total_reg_count = 0 - - try : - reg_addr, reg_bit, reg_count, is_float, is_big_endian, is_sign = get_modbus_comm_info(comm_str) - if self.master == None : - raise Exception("Call set_modbus_master() first to init protocol master") - - float_result_arr = [] - read_reg_count = reg_count - if reg_bit >= 0 : - raise Exception("multi read for reg.bit is not support") - - #读连续寄存器数据, 再添加到浮点数 数组列表 - total_reg_count = read_reg_count * count - result = self.modbus_read_regs(device_addr, reg_addr, total_reg_count) - - for i in range(count) : - if read_reg_count == 4 : - if is_big_endian : - read_value = (result[0] << 48) | (result[1] << 32) | (result[2] << 16) | (result[3] << 0) - else : - read_value = (result[0] << 0) | (result[1] << 16) | (result[2] << 32) | (result[3] << 48) - if is_sign : - read_value = utils.value_u64_to_s64(read_value) - elif read_reg_count == 3 : - if is_big_endian : - read_value = (result[0] << 32) | (result[1] << 16) | (result[2] << 0) - else : - read_value = (result[0] << 0) | (result[1] << 16) | (result[2] << 32) - elif read_reg_count == 2 : - if is_big_endian : - read_value = (result[0] << 16) | (result[1] << 0) - else : - read_value = (result[0] << 0) | (result[1] << 16) - if is_sign : - read_value = utils.value_u32_to_s32(read_value) - elif read_reg_count == 1 : - read_value = result[0] - if is_sign : - read_value = utils.value_u16_to_s16(read_value) - else : - raise Exception("目前只支持读取(1,2,3,4)个寄存器个数") - - if is_float : - fvalue = math.nan - if read_reg_count == 2: - bytes = struct.pack('BBBB', read_value & 0xFF, (read_value >> 8) & 0xFF, (read_value >> 16) & 0xFF, (read_value >> 24) & 0xFF) - fvalue = struct.unpack("> 8) & 0xFF, (low_part >> 16) & 0xFF, (low_part >> 24) & 0xFF) - high_part = (read_value >> 32) & 0xFFFFFFFF - high_bytes = struct.pack('BBBB', high_part & 0xFF, (high_part >> 8) & 0xFF, (high_part >> 16) & 0xFF, (high_part >> 24) & 0xFF) - bytes = low_bytes + high_bytes - fvalue = struct.unpack(" bool: - success = False - write_value = 0 - is_writing = False - is_reading = False - - try : - reg_addr, reg_bit, reg_count, is_float, is_big_endian, is_sign = get_modbus_comm_info(comm_str) - if self.master == None : - raise Exception("Call set_modbus_master() first to init protocol master") - - fvalue_origin = round((fvalue - offset) / scale, 0) - - write_reg_count = reg_count - if reg_bit >= 0 : - write_reg_count = 1 + (int)((reg_bit + reg_count - 1) / 16) - - if write_reg_count > 4 : #寄存器个数大于4个, 目前不支持 - raise Exception("write_reg_count is more than 4") - - write_reg_values = [] #定义空列表 - - if reg_addr >= 100000 and reg_addr < 200000 : #位数据 - if fvalue > 0 : - write_reg_values.append(1) - else : - write_reg_values.append(0) - elif reg_bit >= 0 : - if write_reg_count > 2 : - raise Exception("register count is > 2") - is_reading = True - read_regs = self.modbus_read_regs(device_addr, reg_addr, write_reg_count) - is_reading = False - - origin_read_value = self.modbus_list_to_value(read_regs, is_big_endian) - - write_value = (int)(fvalue_origin) - bit_mask = (0xFFFFFFFF >> (32 - reg_count)) - set_mask = write_value & bit_mask - - modify_value = origin_read_value - modify_value = modify_value & ~(bit_mask << reg_bit) - modify_value = modify_value | (set_mask << reg_bit) - - write_reg_values = self.modbus_value_to_list(modify_value, write_reg_count, is_big_endian) - elif is_float : - if is_big_endian : - format_pack = ">d" if write_reg_count == 4 else ">f" - else : - format_pack = " bool: - success = False - is_writing = False - is_read = False - - try : - reg_addr, reg_bit, reg_count, is_float, is_big_endian, is_sign = get_modbus_comm_info(comm_str) - if self.master == None : - raise Exception("Call set_modbus_master() first to init protocol master") - - write_reg_values = [] - write_reg_count = reg_count - - if reg_bit >= 0 : - raise Exception("multi write for reg.bit is not support") - - if write_reg_count > 4 : #单次写入寄存器个数大于4个, 目前不支持 - raise Exception("write_reg_count is more than 4") - - for fvalue_origin in fvalue_arr: - if reg_addr >= 100000 and reg_addr < 200000 : #位数据 - if fvalue_origin > 0 : - write_reg_values.append(1) - else : - write_reg_values.append(0) - elif is_float : - if is_big_endian : - format_pack = ">d" if write_reg_count == 4 else ">f" - else : - format_pack = " float: - return self.modbus_read_float(device_addr, comm_str, scale, offset) - - #@override 返回 False 表示读取失败, 否则读取成功 - def write_float(self, device_addr, comm_str, fvalue, scale = 1.0, offset = 0.0) -> bool: - return self.modbus_write_float(device_addr, comm_str, fvalue, scale, offset) - - #@override - #读取comm_str地址开始的连续地址count个数, 地址连续 - #返回 math.nan 表示读取失败, 否则读取成功 - def read_float_arr(self, device_addr : int, comm_str : string, count : int) : - return self.modbus_read_float_arr(device_addr, comm_str, count) - - #@override - #写入comm_str地址开始的连续地址 写入总个数由 len(fvalue_arr)决定 - #返回 False 表示读取失败, 否则读取成功 - def write_float_arr(self, device_addr : int, comm_str : string, fvalue_arr : list) -> bool: - return self.modbus_write_float_arr(device_addr, comm_str, fvalue_arr) - - -#串口Modbus_rtu主机类 -class class_protocol_modbus_rtu(class_protocol_modbus) : - def __init__(self, protocol_name = "modbus_rtu") : - class_protocol_modbus.__init__(self, protocol_name) - self.comm_parity = serial.PARITY_NONE - self.comm_bytesize = serial.EIGHTBITS - self.comm_stopbits = serial.STOPBITS_ONE - self.is_open = False - self.comm_uart = None - self.rtu_master : modbus_rtu.RtuMaster = None - return - - #@override - #parity('N', 'E', 'O', 'M', 'S') 选其一, 含义分别代表 ("无校验", "偶校验", "奇校验", "校验1", "校验0"), 缺省为无校验 - #stop(1, 1.5, 2)选其一, 含义分别代表 ("1个停止位", "1.5个停止位", "2个停止位"), 缺省为1个停止位 - #bit(5, 6, 7, 8)选其一, 含义分别代表 ("5位数据", "6位数据", "7位数据","8位数据"), 缺省为8位数据 - #baud(50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600, 19200, 38400, 57600, 115200)选其一, 缺省为9600位数据 - #mode 需要是一个json字符串, exam: "{"name" : 'COM1', "baud" : 115200, "parity" :'E', "stop" : 1}" 代表COM1, 115200波特率, 偶校验, 1停止位 - def open(self, mode : string) : - try : - class_protocol_modbus.mode = mode - mode_dict = json_load_message(mode) - - print_inform_msg(f"打开: 协议名称:{self.protocol_name} ,工作端口:{self.mode}") - except Exception as e: - print_error_msg(f"错误modbus rtu信息:{str(e)}") - mode_dict = None - - if mode_dict : - self.comm_port_name = utils.dict_or_object_get_attr(mode_dict, "name", "COM1") - self.comm_parity = utils.dict_or_object_get_attr(mode_dict, "parity", serial.PARITY_NONE) - self.comm_baud = utils.dict_or_object_get_attr(mode_dict, "baud", 9600) - self.comm_stopbits = utils.dict_or_object_get_attr(mode_dict, "stop", serial.STOPBITS_ONE) - self.comm_bytesize = utils.dict_or_object_get_attr(mode_dict, "bit", serial.EIGHTBITS) - - try : - self.comm_uart = serial.Serial(port= self.comm_port_name, - baudrate= self.comm_baud, - bytesize= self.comm_bytesize, - parity=self.comm_parity, - stopbits=self.comm_stopbits) - - self.rtu_master = modbus_rtu.RtuMaster(self.comm_uart) - self.set_modbus_master(self.rtu_master) - self.set_timeout(self.timeout) - self.is_open = True - except Exception as e: - print_error_msg(f"错误modbus rtu信息:{str(e)}") - self.comm_uart = None - self.is_open = False - - #@override 关闭到modbus rtu 对应的串口 - def close(self) : - if self.is_open : - try : - print_inform_msg(f"关闭 : 协议名称:{self.protocol_name} ,工作端口:{self.mode}") - if self.rtu_master : - self.rtu_master.close() - if self.comm_uart : - self.comm_uart.close() - except Exception as e: - print_error_msg(f"错误关闭modbus rtu信息:{str(e)}") - pass - finally : - self.rtu_master = None - self.comm_uart = None - self.is_open = False - -#以太网Modbus_tcp主机类 -class class_protocol_modbus_tcp(class_protocol_modbus) : - def __init__(self, protocol_name = "modbus_tcp") : - class_protocol_modbus.__init__(self, protocol_name) - self.ip_str = "127.0.0.1" - self.port = 502 - self.tcp_master : modbus_tcp.TcpMaster = None - - return - - #ip: 服务器ip地址, 缺省"127.0.0.1" - #port: 服务器端口, 缺省502 - #timeout: 超时时间, 缺省 5.0S - #mode 需要是一个json字符串, exam: '{"ip" : '192.168.1.201', "port" : 502, "timeout": 5.0}' 代表192.168.1.201, 502端口, 通讯超时 5.0S - def open(self, mode: str): - try: - self.mode = mode - print_inform_msg(f"打开 Modbus TCP: 协议名称:{self.protocol_name} ,工作端口:{self.mode}") - mode_dict = json_load_message(mode) - except json.decoder.JSONDecodeError as e: - print_error_msg(f"解析模式失败: {str(e)}") - mode_dict = None - except Exception as e: - print_error_msg(f"错误打开 Modbus TCP 信息: {str(e)}") - mode_dict = None - - if mode_dict: - self.ip_str = utils.dict_or_object_get_attr(mode_dict, "ip", "127.0.0.1") - self.port = utils.dict_or_object_get_attr(mode_dict, "port", 502) - if "timeout" in mode_dict: - self.timeout = mode_dict["timeout"] - - try: - self.tcp_master = modbus_tcp.TcpMaster(host=self.ip_str, port=self.port, timeout_in_sec=self.timeout) - self.set_modbus_master(self.tcp_master) - self.tcp_master.open() - self.is_open = True - except Exception as e: - print_error_msg(f"打开 Modbus TCP 失败: {str(e)} IP地址:{self.ip_str} ,端口号:{self.port}") - self.is_open = False - - - #关闭到modbus tcp服务器的连接 - def close(self): - if self.is_open or self.tcp_master is not None: - try: - if self.tcp_master: - print_inform_msg(f"关闭 Modbus TCP: 协议名称:{self.protocol_name} ,工作端口:{self.mode}") - self.tcp_master.close() - except Exception as e: - print_error_msg(f"错误关闭 Modbus TCP 信息: {str(e)}") - pass - finally: - self.tcp_master = None - self.is_open = False - print_inform_msg("已断开与 Modbus TCP 服务器的连接") - - - -if __name__ == "__main__": - protocol_modbus_rtu = class_protocol_modbus_rtu("modbus_rtu") - protocol_modbus_rtu.open('{"name" : "COM2", "baud":115200, "parity" :"E", "stop" : 1}') - protocol_modbus_rtu.close() - - protocol_modbus_tcp : class_protocol_modbus_tcp = class_protocol_modbus_tcp("modbus_tcp") - protocol_modbus_tcp.open('{"ip" : "127.0.0.1", "port" : 502, "timeout" : 4.0}') - protocol_modbus_tcp.close() diff --git a/comm_remap.py b/comm_remap.py deleted file mode 100644 index a7831d0..0000000 --- a/comm_remap.py +++ /dev/null @@ -1,19 +0,0 @@ - -COMM_REMAP_MEASURE_SWITCH_STATUS = 0 -COMM_REMAP_MEASURE_SWITCH_ALARM = 2 -COMM_REMAP_MEASURE_FLOAT_IA = 4 -COMM_REMAP_MEASURE_FLOAT_IB = 5 -COMM_REMAP_MEASURE_FLOAT_IC = 6 -COMM_REMAP_MEASURE_FLOAT_UAB = 10 -COMM_REMAP_MEASURE_FLOAT_UBC = 12 -COMM_REMAP_MEASURE_FLOAT_UCA = 14 -COMM_REMAP_MEASURE_FLOAT_RO = 16 -COMM_REMAP_MEASURE_FLOAT_IO = 18 -COMM_REMAP_MEASURE_FLOAT_UO = 20 - - -COMM_REMAP_PARA_CURRENT_RATE = 1000 -COMM_REMAP_PARA_CURRENT_SHORT_MUL = 1002 -COMM_REMAP_PARA_RATE_VOLTAGE = 1004 -COMM_REMAP_PARA_LOW_VOLTAGE_RATIO = 1006 -COMM_REMAP_PARA_LOW_VOLTAGE_DELAY = 1008 \ No newline at end of file diff --git a/comm_thread.py b/comm_thread.py deleted file mode 100644 index 8db1f4a..0000000 --- a/comm_thread.py +++ /dev/null @@ -1,78 +0,0 @@ -import threading -from threading import Thread -import time -import menu_utils as utils -from comm_device import class_comm_device -from print_color import * - -class class_comm_master_thread(Thread): - thread_object_id = 0 - CHECK_INTERVAL = 0.05 # 检查间隔(秒) - MAX_FAIL_TIME = 5 # 最大失败时间(秒) - - def __init__(self, - device_comm_object_list=None, - thread_name="device"): - super().__init__() - self.stop_request = False - self.device_comm_object_list = device_comm_object_list if device_comm_object_list is not None else [] - - if thread_name is None: - thread_name = "device" + str(class_comm_master_thread.thread_object_id) - class_comm_master_thread.thread_object_id += 1 - - self.thread_name = thread_name - - def close(self): - self.stop_request = True - - def run(self): - print_inform_msg(f"{self.thread_name} modbus 主线程启动") - - total_fail_time = 0 - base_time = time.time() - - while not self.stop_request: - comm_success_count = 0 - total_comm_count = 0 - - for device in self.device_comm_object_list: - try: - if device.comm_active: - success_count, comm_count = device.device_comm_cycle() - comm_success_count += success_count - total_comm_count += comm_count - except Exception as err: - print_error_msg(err) - - cur_time = time.time() - - if comm_success_count > 0: - total_fail_time = 0 - elif total_comm_count > 0: - total_fail_time += cur_time - base_time - base_time = cur_time - - if total_fail_time >= self.MAX_FAIL_TIME: - self.reconnect_devices() - total_fail_time = 0 - - time.sleep(self.CHECK_INTERVAL) - - print_error_msg(f"{self.thread_name} modbus 主线程停止") - - def reconnect_devices(self): - """重新连接所有设备的协议""" - for device in self.device_comm_object_list: - try: - device.protocol.close() - except Exception as err: - print_error_msg(f"关闭协议时出错: {err}") - - for device in self.device_comm_object_list: - try: - device.protocol.open(device.protocol.mode) - except Exception as err: - print_error_msg(f"重新打开协议时出错: {err}") - - print_warning_msg("与保护器连接超时, 重新进行连接") diff --git a/data/Users.csv b/data/Users.csv index f1b2d56..35259ef 100644 --- a/data/Users.csv +++ b/data/Users.csv @@ -1,3 +1,2 @@ -Student_Name,Student_PRN,Student_Email,Student_Whatsapp_no,Student_pass,Branch,Semester,ssid -Ravikiran Yavalkar,12444444,abcd.efgh24@gmail.com,9607111115,India,AIML-F,III,NULL -测试用户,11111111,test@example.com,NULL,0000,测试,III,zhizhan-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 diff --git a/device_conf.py b/device_conf.py deleted file mode 100644 index 05284b3..0000000 --- a/device_conf.py +++ /dev/null @@ -1,127 +0,0 @@ -import menu_page -import menu_utils as utils - - -def func_comm_test_leak_exam(object_device, topic_item, topic, message) : - return None - -def func_comm_table_trigger_item_exam(object_comm_table, comm_table_item) : - return False - - -exam_menu_alias_table = [ - {"alias_bool": {0:"关闭", 1:"打开"}}, -] - -exam_mqtt_topic_table = [ - {"name": "test_exam", "execute": func_comm_test_leak_exam}, -] - -exam_measure_pack = [ - { - "name": "OnStatus", - "addr": "8162.0", - "alias": "alias_onoff", - }, -] - -exam_comm_table = [ - {"name":"measure", "reg_addr":8139, "reg_count":35, "cycle": 200, "mqtt_pack": "exam_measure_pack"}, -] - -exam_menu_top = [ - { - "name": "退出", - "action": "exit", - }, -] - -exam_menu_caption = [ - {"name" : "exam_menu_top", "menu" : exam_menu_top, "next" : exam_menu_top, "prev" : exam_menu_top, "caption": "测试菜单", "page" : 10, "max_items" : 8}, -] - -#通讯设备配置基类, 不同的modbus设备需要重载各个函数 -class class_comm_device_config : - def __init__(self): - pass - - #获取别名表 - def get_alias_table(self) : - return exam_menu_alias_table - - #获取通讯数据表, 及触发函数 - def get_comm_table(self) : - return exam_comm_table, func_comm_table_trigger_item_exam - - #获取主菜单 - def get_menu_top(self) : - return exam_menu_top - - #获取mqtt表, 实现mqtt通讯 - def get_mqtt_table(self) : - return exam_mqtt_topic_table - - #获取昆仑通态显示页面 - def menu_get_display_page(self, active_menu): - return menu_page.KUNLUN_GRAOUP_PAGE_MENU - - def get_menu_caption_info(self) : - return exam_menu_caption - - def modify_menu_item(self, menu_item, value) : - return False - #获取菜单相关信息 - def search_menu_info(self, menu_name) : - search_dict = None - list_caption_info = self.get_menu_caption_info() - for menu_dict in list_caption_info : - if "name" in menu_dict.keys() : - if menu_dict["name"] == menu_name : - search_dict = menu_dict - break - return search_dict - - #获取菜单相关信息 - def search_object_menu_info(self, menu_object) : - search_dict = None - list_caption_info = self.get_menu_caption_info() - for menu_dict in list_caption_info : - search_menu_object = utils.dict_or_object_get_attr(menu_dict, "menu", None) - if search_menu_object == menu_object : - search_dict = menu_dict - break - return search_dict - - #获取自身菜单 - def get_menu(self, menu_name) : - if menu_name != None : - search_dict = self.search_menu_info(menu_name) - if search_dict != None : - return utils.dict_or_object_get_attr(search_dict, "menu", None) - return None - - #获取自身菜单 - def get_menu_name(self, menu_object) : - menu_name = None - search_dict = self.search_object_menu_info(menu_object) - if search_dict != None : - menu_name = utils.dict_or_object_get_attr(search_dict, "name", None) - return menu_name - - #获取下一个兄弟菜单 - def get_menu_next(self, menu_name) : - search_dict = self.search_menu_info(menu_name) - menu_name = utils.dict_or_object_get_attr(search_dict, "next", None) - return self.get_menu(menu_name) - - #获取上一个兄弟菜单 - def get_menu_next(self, menu_name) : - search_dict = self.search_menu_info(menu_name) - menu_name = utils.dict_or_object_get_attr(search_dict, "prev", None) - return self.get_menu(menu_name) - - #获取菜单显示页面 - def get_menu_page(self, menu_name) : - search_dict = self.search_menu_info(menu_name) - page = utils.dict_or_object_get_attr(search_dict, "page", menu_page.KUNLUN_GRAOUP_PAGE_MENU) - return page \ No newline at end of file diff --git a/kv/app.kv b/kv/app.kv index 9a9b425..c367525 100644 --- a/kv/app.kv +++ b/kv/app.kv @@ -4,7 +4,12 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 HomeScreen: # 首页屏幕 name: 'home' # 首页,显示应用主要内容和功能入口 LoginScreen: # 登录屏幕 - name: 'login' # 用户登录界面,输入账号密码等 + name: 'login' # 用户认证界面 + ProfileScreen: # 个人资料屏幕 + name: "profile" # 显示用户个人信息的界面 + HistoryScreen: # 历史记录屏幕 + name: 'history' # 显示用户操作历史 + SignUpScreen: # 注册屏幕 name: 'signup' # 用户注册界面,创建新账号 OtpScreen: # 验证码屏幕 @@ -13,10 +18,6 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 name: 'reset_pass' # 重置密码界面,设置新密码 ForgetPassScreen: # 忘记密码屏幕 name: 'forgot_pass' # 忘记密码入口,用于启动密码找回流程 - ProfileScreen: # 个人资料屏幕 - name: "profile" # 显示用户个人信息的界面 - HistoryScreen: # 历史记录屏幕 - name: 'history' # 显示用户操作历史 RecommendScreen: # 推荐屏幕 name: 'recommend' # 显示推荐内容 SearchBookScreen: # 搜索书籍屏幕 @@ -32,6 +33,25 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 RenewBookScreen: # 续借书籍屏幕 name: 'renew_book' # 处理书籍续借操作的界面 + ModifyCurrentParamScreen: # 修改参数屏幕 + name: 'modify_current_param' # 用于修改系统参数的界面 + ModifyVoltageParamScreen: # 修改电压参数屏幕 + name: 'modify_voltage_param' # 用于修改电压参数的界面 + ModifyLeakageParamScreen: # 修改漏电参数屏幕 + name: 'modify_leakage_param' # 用于修改漏电参数的 + ModifySystemParamScreen: # 修改系统参数屏幕 + name: 'modify_system_param' # 用于修改系统设置的界面 + ModifyProtectionParamScreen: # 修改保护参数屏幕 + name: 'modify_protection_param' # 用于修改保护参数的界面 + RealTimeCurveScreen: # 实时曲线屏幕 + name: 'real_time_curve' # 显示实时数据曲线的界面 + ControlCommandScreen: # 控制命令屏幕 + name: 'control_command' # 用于发送控制命令的界面 + + AboutScreen: # 关于屏幕 + name: 'about' # 显示应用信息和开发者信息的界 + + : MDFloatLayout: @@ -136,194 +156,17 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 MDActionBottomAppBarButton: icon: "tools" pos_hint:{'center_x':0.38, 'center_y': 0.5} - on_press: root.manager.current = 'borrow_book' + on_press: root.manager.current = 'control_command' MDActionBottomAppBarButton: icon: "alert" pos_hint:{'center_x':0.61, 'center_y': 0.5} - on_press: root.manager.current = 'recommend' + on_press: root.manager.current = 'history' MDActionBottomAppBarButton: icon: "chart-bell-curve-cumulative" pos_hint:{'center_x':0.85, 'center_y': 0.5} on_press: - root.manager.current = 'history' - app.book_history() - - - # Carousel at the top - # Carousel: - # id: carousel - # size_hint_y: None - # height: "205dp" - # width: self.parent.width - # pos_hint: {'top': .918} # Adjust position to fit below the AppBar - # loop: False - # anim_type: 'in_out_quad' - # anim_move_duration: 0.2 - # BoxLayout: - # orientation: 'vertical' - - - # Image: - # source: 'assets/lib_img1.jpg' - # allow_stretch: True - # keep_ratio: False - - # MDLabel: - # text: "Bajrangdas Lohiya Central Library" - # font_name: "BPoppins" - # font_size: "24sp" - # size_hint0: None, None - # bold: True - # width: self.parent.width - # padding: "12dp",0,0,"5dp" - # color: rgba(255, 255, 255, 255) - - # BoxLayout: - # orientation: 'vertical' - - # Image: - # source: 'assets/Book_rack.jpg' - # allow_stretch: True - # keep_ratio: False - - # MDLabel: - # text: "Vast Book Collection (80,000+)" - # font_name: "BPoppins" - # font_size: "24sp" - # size_hint0: None, None - # width: self.parent.width - # padding: "12dp",0,0,"5dp" - # color: rgba(255, 255, 255, 255) - - # BoxLayout: - # orientation: 'vertical' - - # Image: - # source: 'assets/reading_space.jpg' - # allow_stretch: True - # keep_ratio: False - - # MDLabel: - # text: "Quiet Room" - # font_name: "BPoppins" - # font_size: "24sp" - # size_hint0: None, None - # width: self.parent.width - # padding: "12dp",0,0,"5dp" - # color: rgba(255, 255, 255, 255) - - - # BoxLayout: - # orientation: 'vertical' - - # Image: - # source: 'assets/journal_section.jpg' - # allow_stretch: True - # keep_ratio: False - - # MDLabel: - # text: "National & International Journals & Research Paper" - # font_name: "BPoppins" - # font_size: "24sp" - # size_hint0: None, None - # width: self.parent.width - # padding: "12dp",0,0,"5dp" - # color: rgba(255, 255, 255, 255) - - - - - # BoxLayout: - # orientation: 'vertical' - - # Image: - # source: 'assets/lib_img2.jpg' - # allow_stretch: True - # keep_ratio: False - - # MDLabel: - # text: "Reference Section" - # font_name: "BPoppins" - # font_size: "24sp" - # size_hint0: None, None - # width: self.parent.width - # padding: "12dp",0,0,"5dp" - # color: rgba(255, 255, 255, 255) - - - # BoxLayout: - # orientation: 'vertical' - - # Image: - # source: 'assets/lib_img3.jpg' - # allow_stretch: True - # keep_ratio: False - - # MDLabel: - # text: "Career and Test Preparation Section:" - # font_name: "BPoppins" - # font_size: "24sp" - # size_hint0: None, None - # width: self.parent.width - # padding: "12dp",0,0,"5dp" - # color: rgba(255, 255, 255, 255) - - # BoxLayout: - # orientation: 'vertical' - - # Image: - # source: 'assets/pc1.jpg' - # allow_stretch: True - # keep_ratio: False - - # MDLabel: - # text: "Online E-Resources" - # font_name: "BPoppins" - # font_size: "24sp" - # size_hint0: None, None - # width: self.parent.width - # padding: "12dp",0,0,"5dp" - # color: rgba(255, 255, 255, 255) - - # BoxLayout: - # orientation: 'vertical' - - # Image: - # source: 'assets/keyboard.jpg' - # allow_stretch: True - # keep_ratio: False - - # MDLabel: - # text: "iThenticate Software for Plagiarism checking" - # font_name: "BPoppins" - # font_size: "24sp" - # size_hint0: None, None - # width: self.parent.width - # padding: "12dp",0,0,"5dp" - # color: rgba(255, 255, 255, 255) - - # Navigation Buttons Positioned Over the Carousel - # MDIconButton: - # icon: "arrow-left-thin-circle-outline" - # pos_hint: {'x': 0.025, 'center_y': 0.7705} # Adjusted position - # size_hint: None, None - # size: "48dp", "48dp" - # user_font_size: "30sp" - # theme_text_color: "Custom" - # text_color: (1,1,1,1) - # on_release: carousel.load_previous() - # disabled: carousel.index == 0 - - # MDIconButton: - # icon: "arrow-right-thin-circle-outline" - # pos_hint: {'right': 0.9725, 'center_y': 0.7705} - # size_hint: None, None - # size: "48dp", "48dp" - # user_font_size: "30sp" - # theme_text_color: "Custom" - # text_color: (1,1,1,1) - # on_release: carousel.load_next() - # disabled: carousel.index == len(carousel.slides) - 1 + root.manager.current = 'real_time_curve' + # app.book_history() ScrollView: size_hint: 1, None @@ -483,6 +326,8 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 DrawerClickableItem: icon: "current-dc" + # right_text: '+99' + # text_right_color: "#4a4930" text: "电流设置" font_style: "H6" on_touch_down: app.change_cursor(True) @@ -574,7 +419,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 on_release: root.manager.transition.direction = "left" nav_drawer.set_state('close') - app.book_history() + # app.book_history() root.manager.current = "history" DrawerClickableItem: @@ -799,368 +644,368 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 # root.manager.transition.direction = "left" # root.manager.current="signup" -: - name: "signup" - MDFloatLayout: - mg_bd_color: 1,1,1,1 - MDIconButton: - icon: "arrow-left" - pos_hint: {'center_y': 0.95} - user_font_size: "30sp" - theme_text_color: "Custom" - text_color: rgba(26,24,58,255) - on_touch_down: app.change_cursor(True) - on_touch_up: app.change_cursor(False) - on_release: - root.manager.transition.direction= 'right' - root.manager.current= "main" - MDLabel: - text: "H i!" - font_name: "RPac" - font_size: "26sp" - size_hint_x: None - width: dp(350) - pos_hint: {'center_x': 0.5,'center_y': 0.9} - color: rgba(0, 0, 59, 255) +# : +# name: "signup" +# MDFloatLayout: +# mg_bd_color: 1,1,1,1 +# MDIconButton: +# icon: "arrow-left" +# pos_hint: {'center_y': 0.95} +# user_font_size: "30sp" +# theme_text_color: "Custom" +# text_color: rgba(26,24,58,255) +# on_touch_down: app.change_cursor(True) +# on_touch_up: app.change_cursor(False) +# on_release: +# root.manager.transition.direction= 'right' +# root.manager.current= "main" +# MDLabel: +# text: "H i!" +# font_name: "RPac" +# font_size: "26sp" +# size_hint_x: None +# width: dp(350) +# pos_hint: {'center_x': 0.5,'center_y': 0.9} +# color: rgba(0, 0, 59, 255) - MDLabel: - text: "Create a new account" - font_name: "BPoppins" - font_size: "20sp" - size_hint_x: None - width: dp(350) - pos_hint: {'center_x': 0.5,'center_y': 0.85} - color: app.theme_cls.primary_color +# MDLabel: +# text: "Create a new account" +# font_name: "BPoppins" +# font_size: "20sp" +# size_hint_x: None +# width: dp(350) +# pos_hint: {'center_x': 0.5,'center_y': 0.85} +# color: app.theme_cls.primary_color - ScrollView: - size_hint: 1, None - height: self.parent.height - dp(250) - pos_hint: {'top':0.81} - MDList: - padding: "12dp", "10dp", "12dp", "3dp" - spacing: "10dp" - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDLabel: - text: "Name" - color: rgba(0, 0, 0, 255) - font_name: "BPoppins" - font_size: '15sp' - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} +# ScrollView: +# size_hint: 1, None +# height: self.parent.height - dp(250) +# pos_hint: {'top':0.81} +# MDList: +# padding: "12dp", "10dp", "12dp", "3dp" +# spacing: "10dp" +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDLabel: +# text: "Name" +# color: rgba(0, 0, 0, 255) +# font_name: "BPoppins" +# font_size: '15sp' +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} - MDRelativeLayout: - size_hint_y: None - height: "60dp" - MDTextField: - id: signup_name - hint_text: "Enter Name*" - font_name: "MPoppins" - font_size: "15sp" - helper_text: "Provide your fullname" - helper_text_mode: "on_focus" - icon_right: "alphabetical" - icon_color: app.theme_cls.primary_color - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} - on_touch_down: app.change_cursor(True) - on_touch_up: app.change_cursor(False) - canvas.before: - Color: - rgb: rgba(127, 127, 127, 255) - Line: - width: 0.5 - rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDLabel: - text: "PRN" - color: rgba(0, 0, 0, 255) - font_name: "BPoppins" - font_size: '15sp' - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} +# MDRelativeLayout: +# size_hint_y: None +# height: "60dp" +# MDTextField: +# id: signup_name +# hint_text: "Enter Name*" +# font_name: "MPoppins" +# font_size: "15sp" +# helper_text: "Provide your fullname" +# helper_text_mode: "on_focus" +# icon_right: "alphabetical" +# icon_color: app.theme_cls.primary_color +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} +# on_touch_down: app.change_cursor(True) +# on_touch_up: app.change_cursor(False) +# canvas.before: +# Color: +# rgb: rgba(127, 127, 127, 255) +# Line: +# width: 0.5 +# rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDLabel: +# text: "PRN" +# color: rgba(0, 0, 0, 255) +# font_name: "BPoppins" +# font_size: '15sp' +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} - MDRelativeLayout: - size_hint_y: None - height: "60dp" - MDTextField: - id: signup_prn - hint_text: "Provide your PRN*" - font_name: "MPoppins" - font_size: "15sp" - helper_text: "PRN of 8 digits starting with 1 2 ......only*" - helper_text_mode: "on_focus" - icon_right: "dialpad" - input_filter: 'int' - required_length: 8 - icon_color: app.theme_cls.primary_color - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} - on_touch_down: app.change_cursor(True) - on_touch_up: app.change_cursor(False) - canvas.before: - Color: - rgb: rgba(127, 127, 127, 255) - Line: - width: 0.5 - rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDLabel: - text: "Email" - color: rgba(0, 0, 0, 255) - font_name: "BPoppins" - font_size: '15sp' - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} +# MDRelativeLayout: +# size_hint_y: None +# height: "60dp" +# MDTextField: +# id: signup_prn +# hint_text: "Provide your PRN*" +# font_name: "MPoppins" +# font_size: "15sp" +# helper_text: "PRN of 8 digits starting with 1 2 ......only*" +# helper_text_mode: "on_focus" +# icon_right: "dialpad" +# input_filter: 'int' +# required_length: 8 +# icon_color: app.theme_cls.primary_color +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} +# on_touch_down: app.change_cursor(True) +# on_touch_up: app.change_cursor(False) +# canvas.before: +# Color: +# rgb: rgba(127, 127, 127, 255) +# Line: +# width: 0.5 +# rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDLabel: +# text: "Email" +# color: rgba(0, 0, 0, 255) +# font_name: "BPoppins" +# font_size: '15sp' +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} - MDRelativeLayout: - size_hint_y: None - height: "60dp" - MDTextField: - id: signup_email - hint_text: "邮箱地址*" - font_name: "MPoppins" - font_size: "15sp" - helper_text: "email test*" - helper_text_mode: "on_focus" - icon_right: "email-arrow-left-outline" - min_text_length: 11 - icon_color: app.theme_cls.primary_color - size_hint_x: None - width: 335 - pos_hint: {"center_x": 0.5, "center_y": 0.5} - on_touch_down: app.change_cursor(True) - on_touch_up: app.change_cursor(False) - canvas.before: - Color: - rgb: rgba(127, 127, 127, 255) - Line: - width: 0.5 - rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 +# MDRelativeLayout: +# size_hint_y: None +# height: "60dp" +# MDTextField: +# id: signup_email +# hint_text: "email address*" +# font_name: "MPoppins" +# font_size: "15sp" +# helper_text: "email test*" +# helper_text_mode: "on_focus" +# icon_right: "email-arrow-left-outline" +# min_text_length: 11 +# icon_color: app.theme_cls.primary_color +# size_hint_x: None +# width: 335 +# pos_hint: {"center_x": 0.5, "center_y": 0.5} +# on_touch_down: app.change_cursor(True) +# on_touch_up: app.change_cursor(False) +# canvas.before: +# Color: +# rgb: rgba(127, 127, 127, 255) +# Line: +# width: 0.5 +# rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDLabel: - text: "电话" - color: rgba(0, 0, 0, 255) - font_name: "BPoppins" - font_size: '15sp' - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDLabel: +# text: "电话" +# color: rgba(0, 0, 0, 255) +# font_name: "BPoppins" +# font_size: '15sp' +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} - MDRelativeLayout: - size_hint_y: None - height: "60dp" - MDTextField: - id: signup_no - hint_text: "Enter WhatsApp Number*" - font_name: "MPoppins" - font_size: "15sp" - helper_text: "Provide your Whatsapp no. only*" - helper_text_mode: "on_focus" - icon_right: "whatsapp" - icon_color: app.theme_cls.primary_color - input_filter: 'int' - max_text_length: 10 - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} - on_touch_down: app.change_cursor(True) - on_touch_up: app.change_cursor(False) - canvas.before: - Color: - rgb: rgba(127, 127, 127, 255) - Line: - width: 0.5 - rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 +# MDRelativeLayout: +# size_hint_y: None +# height: "60dp" +# MDTextField: +# id: signup_no +# hint_text: "Enter WhatsApp Number*" +# font_name: "MPoppins" +# font_size: "15sp" +# helper_text: "Provide your Whatsapp no. only*" +# helper_text_mode: "on_focus" +# icon_right: "whatsapp" +# icon_color: app.theme_cls.primary_color +# input_filter: 'int' +# max_text_length: 10 +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} +# on_touch_down: app.change_cursor(True) +# on_touch_up: app.change_cursor(False) +# canvas.before: +# Color: +# rgb: rgba(127, 127, 127, 255) +# Line: +# width: 0.5 +# rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDLabel: - text: "Password" - color: rgba(0, 0, 0, 255) - font_name: "BPoppins" - font_size: '15sp' - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} - spacing: "10dp" +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDLabel: +# text: "Password" +# color: rgba(0, 0, 0, 255) +# font_name: "BPoppins" +# font_size: '15sp' +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} +# spacing: "10dp" - MDRelativeLayout: - size_hint_y: None - height: "60dp" - MDRelativeLayout: - size: self.width, self.height - MDTextField: - id : signup_pass - font_name: "MPoppins" - font_size: "15sp" - hint_text: "Create Password*" - helper_text: "must contain 8 char* with at least one 'a' , 'A' , '@' & '0'" - helper_text_mode: "on_focus" - password:True - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} - on_focus: app.focus_text_field(icon, self.focus, "sign_pass") - on_touch_down: app.change_cursor(True) - on_touch_up: app.change_cursor(False) - canvas.before: - Color: - rgb: rgba(127, 127, 127, 255) - Line: - width: dp(0.5) - rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 +# MDRelativeLayout: +# size_hint_y: None +# height: "60dp" +# MDRelativeLayout: +# size: self.width, self.height +# MDTextField: +# id : signup_pass +# font_name: "MPoppins" +# font_size: "15sp" +# hint_text: "Create Password*" +# helper_text: "must contain 8 char* with at least one 'a' , 'A' , '@' & '0'" +# helper_text_mode: "on_focus" +# password:True +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} +# on_focus: app.focus_text_field(icon, self.focus, "sign_pass") +# on_touch_down: app.change_cursor(True) +# on_touch_up: app.change_cursor(False) +# canvas.before: +# Color: +# rgb: rgba(127, 127, 127, 255) +# Line: +# width: dp(0.5) +# rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 - MDIconButton: - id: icon - icon: 'eye-off' - theme_icon_color: "Custom" - icon_color: rgba(217, 217, 217, 255) - size_hint: None, None - size: dp(24), dp(24) - pos: signup_pass.x + signup_pass.width - self.width+dp(4), signup_pass.center_y - self.height / 2+dp(5) - on_touch_down: app.change_cursor(True) - on_touch_up: app.change_cursor(False) - on_release: - app.toggle_password_visibility(signup_pass, self) - signup_pass.focus=True +# MDIconButton: +# id: icon +# icon: 'eye-off' +# theme_icon_color: "Custom" +# icon_color: rgba(217, 217, 217, 255) +# size_hint: None, None +# size: dp(24), dp(24) +# pos: signup_pass.x + signup_pass.width - self.width+dp(4), signup_pass.center_y - self.height / 2+dp(5) +# on_touch_down: app.change_cursor(True) +# on_touch_up: app.change_cursor(False) +# on_release: +# app.toggle_password_visibility(signup_pass, self) +# signup_pass.focus=True - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDLabel: - text: "Branch" - color: rgba(0, 0, 0, 255) - font_name: "BPoppins" - font_size: '15sp' - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDLabel: +# text: "Branch" +# color: rgba(0, 0, 0, 255) +# font_name: "BPoppins" +# font_size: '15sp' +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} - MDRelativeLayout: - size_hint_y: None - height: "60dp" - MDTextField: - id: signup_branch - hint_text: "Branch*" - font_name: "MPoppins" - font_size: "15sp" - helper_text: "Provide your Branch" - helper_text_mode: "on_focus" - icon_right: "source-branch" - min_text_length: 11 - icon_color: app.theme_cls.primary_color - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} - on_touch_down: app.change_cursor(True) - on_touch_up: app.change_cursor(False) - canvas.before: - Color: - rgb: rgba(127, 127, 127, 255) - Line: - width: dp(0.5) - rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 +# MDRelativeLayout: +# size_hint_y: None +# height: "60dp" +# MDTextField: +# id: signup_branch +# hint_text: "Branch*" +# font_name: "MPoppins" +# font_size: "15sp" +# helper_text: "Provide your Branch" +# helper_text_mode: "on_focus" +# icon_right: "source-branch" +# min_text_length: 11 +# icon_color: app.theme_cls.primary_color +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} +# on_touch_down: app.change_cursor(True) +# on_touch_up: app.change_cursor(False) +# canvas.before: +# Color: +# rgb: rgba(127, 127, 127, 255) +# Line: +# width: dp(0.5) +# rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDRelativeLayout: - size_hint_y: None - height: "5dp" - MDLabel: - text: "Semester" - color: rgba(0, 0, 0, 255) - font_name: "BPoppins" - font_size: '15sp' - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDRelativeLayout: +# size_hint_y: None +# height: "5dp" +# MDLabel: +# text: "Semester" +# color: rgba(0, 0, 0, 255) +# font_name: "BPoppins" +# font_size: '15sp' +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} - MDRelativeLayout: - size_hint_y: None - height: "60dp" - MDTextField: - id: signup_sem - hint_text: "Semester*" - font_name: "MPoppins" - font_size: "15sp" - helper_text: "Provide your Branch" - helper_text_mode: "on_focus" - icon_right: "roman-numeral-2" - min_text_length: 11 - icon_color: app.theme_cls.primary_color - size_hint_x: None - width: dp(335) - pos_hint: {"center_x": 0.5, "center_y": 0.5} - on_touch_down: app.change_cursor(True) - on_touch_up: app.change_cursor(False) - canvas.before: - Color: - rgb: rgba(127, 127, 127, 255) - Line: - width: dp(0.5) - rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 +# MDRelativeLayout: +# size_hint_y: None +# height: "60dp" +# MDTextField: +# id: signup_sem +# hint_text: "Semester*" +# font_name: "MPoppins" +# font_size: "15sp" +# helper_text: "Provide your Branch" +# helper_text_mode: "on_focus" +# icon_right: "roman-numeral-2" +# min_text_length: 11 +# icon_color: app.theme_cls.primary_color +# size_hint_x: None +# width: dp(335) +# pos_hint: {"center_x": 0.5, "center_y": 0.5} +# on_touch_down: app.change_cursor(True) +# on_touch_up: app.change_cursor(False) +# canvas.before: +# Color: +# rgb: rgba(127, 127, 127, 255) +# Line: +# width: dp(0.5) +# rounded_rectangle: self.x-5, self.y+20, self.width+10, self.height-25, 10,10,10,10,100 - MDRelativeLayout: - size_hint_y: None - height: "65dp" - Button: - text: "Get OTP" - font_name: "BPoppins" - size_hint: None, None - width: dp(300) - height: dp(59) - pos_hint: {'center_x': 0.5, 'center_y': 1} - background_color: 0,0,0,0 - on_touch_down: app.change_cursor(True) - on_touch_up: app.change_cursor(False) - on_release: - root.manager.transition.direction = "up" - app.otp_button_fun(False) - app.on_start() - app.check_signup(signup_name.text, signup_prn.text, signup_email.text, signup_no.text, signup_pass.text, signup_branch.text, signup_sem.text) - canvas.before: - Color: - rgb: rgba(52, 0, 231, 255) - RoundedRectangle: - size: self.size - pos: self.pos - radius: [10] +# MDRelativeLayout: +# size_hint_y: None +# height: "65dp" +# Button: +# text: "Get OTP" +# font_name: "BPoppins" +# size_hint: None, None +# width: dp(300) +# height: dp(59) +# pos_hint: {'center_x': 0.5, 'center_y': 1} +# background_color: 0,0,0,0 +# on_touch_down: app.change_cursor(True) +# on_touch_up: app.change_cursor(False) +# on_release: +# root.manager.transition.direction = "up" +# app.otp_button_fun(False) +# app.on_start() +# app.check_signup(signup_name.text, signup_prn.text, signup_email.text, signup_no.text, signup_pass.text, signup_branch.text, signup_sem.text) +# canvas.before: +# Color: +# rgb: rgba(52, 0, 231, 255) +# RoundedRectangle: +# size: self.size +# pos: self.pos +# radius: [10] : @@ -1234,7 +1079,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 app.on_start() root.manager.transition.direction = "up" app.otp_button_fun("True") - app.verify_no() + # app.verify_no() canvas.before: Color: rgb: rgba(52, 0, 231, 255) @@ -1689,17 +1534,17 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 MDActionBottomAppBarButton: icon: "tools" pos_hint:{'center_x':0.38, 'center_y': 0.5} - on_press: root.manager.current = 'borrow_book' + on_press: root.manager.current = 'control_command' MDActionBottomAppBarButton: icon: "alert" pos_hint:{'center_x':0.61, 'center_y': 0.5} - on_press: root.manager.current = 'recommend' + on_press: root.manager.current = 'history' MDActionBottomAppBarButton: icon: "chart-bell-curve-cumulative" pos_hint:{'center_x':0.85, 'center_y': 0.5} on_press: - root.manager.current = 'history' - app.book_history() + root.manager.current = 'real_time_curve' + # app.book_history() MDIconButton: icon: "arrow-left" @@ -1770,7 +1615,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 pos_hint:{'center_x':0.85, 'center_y': 0.5} on_press: root.manager.current = 'history' - app.book_history() + # app.book_history() MDIconButton: @@ -1851,7 +1696,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 pos_hint:{'center_x':0.85, 'center_y': 0.5} on_press: root.manager.current = 'history' - app.book_history() + # app.book_history() MDIconButton: @@ -1933,7 +1778,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 pos_hint:{'center_x':0.85, 'center_y': 0.5} on_press: root.manager.current = 'history' - app.book_history() + # app.book_history() @@ -2203,7 +2048,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 pos_hint:{'center_x':0.85, 'center_y': 0.5} on_press: root.manager.current = 'history' - app.book_history() + # app.book_history() MDIconButton: icon: "arrow-left" @@ -2252,7 +2097,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 pos_hint:{'center_x':0.85, 'center_y': 0.5} on_press: root.manager.current = 'history' - app.book_history() + # app.book_history() @@ -2373,7 +2218,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 pos_hint:{'center_x':0.85, 'center_y': 0.5} on_press: root.manager.current = 'history' - app.book_history() + # app.book_history() @@ -2447,7 +2292,7 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 pos_hint:{'center_x':0.85, 'center_y': 0.5} on_press: root.manager.current = 'history' - app.book_history() + # app.book_history() @@ -2493,3 +2338,590 @@ ScreenManager: # 屏幕管理器,用于管理应用中所有的屏幕及其 id : renew_grid padding: "1dp", "50dp", "12dp", "30dp" spacing: "50dp" + +: + MDFloatLayout: # 使用浮动布局,可以自由控制子组件的位置 + orientation: 'vertical' + md_bd_color: 1,1,1,1 + anchor_x: 'center' # 水平居中锚点 + anchor_y: 'center' # 垂直居中锚点 + + BoxLayout: + orientation: 'vertical' + size_hint_y: None + height: "54dp" + pos_hint: {"top": 1} + MDTopAppBar: + title: "实时曲线" + title_font_style: "H5" + halign: 'center' + elevation: 10 + + + MDBottomAppBar: # 底部导航栏 + height: "62dp" + elevation: 10 # 阴影高度 + MDActionBottomAppBarButton: # 首页按钮 + icon: "home" + pos_hint:{'center_x':0.15, 'center_y': 0.5} + on_press: root.manager.current = 'home' + MDActionBottomAppBarButton: # 控制按钮 + icon: "tools" + pos_hint:{'center_x':0.38, 'center_y': 0.5} + on_press: root.manager.current = 'control_command' + MDActionBottomAppBarButton: # 历史报警按钮 + icon: "alert" + pos_hint:{'center_x':0.61, 'center_y': 0.5} + on_press: root.manager.current = 'history' + MDActionBottomAppBarButton: # 实时曲线按钮 + icon: "chart-bell-curve-cumulative" + pos_hint:{'center_x':0.85, 'center_y': 0.5} + on_press: + root.manager.current = 'real_time_curve' + + MDIconButton: # 返回按钮(箭头) + icon: "arrow-left" + pos_hint: {'center_y': 0.95} + theme_text_color: "Custom" + text_color: rgba(26,24,58,255) + size_hint_x: None + width: dp(500) + on_touch_down: app.change_cursor(True) # 按下时改变光标 + on_touch_up: app.change_cursor(False) # 释放时恢复光标 + on_release: + root.manager.transition.direction = 'right' # 页面切换方向 + root.manager.current = "home" # 返回首页 + app.on_press_back_arrow() # 执行返回操作 + + ScrollView: # 可滚动区域 + size_hint: 1, None + height: self.parent.height - dp(150) + pos_hint: {'top':0.895} + MDList: + # id : image_label_grid + padding: "20dp", "40dp", "12dp", "17dp" + spacing: "50dp" + + MDLabel: + text: "测试" + font_name: "BPoppins" + font_size: "24sp" + pos_hint: {'center_x': 0.45} + halign: 'center' + bold: True + color: rgba(0, 0, 0, 255) + MDLabel: + text: "曲线" + font_name: "BPoppins" + font_size: "24sp" + size_hint_x: None + width: dp(400) + padding: "12dp" + pos_hint: {'center_x': 0.5, 'center_y': 0.9} + color: rgba(0, 0, 59, 255) + MDLabel: + id: register_label + text: "通信超时" + 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) # 绑定修改方法 + # CurveWidget: + # size_hint_y: None + # height: dp(300) + + + +: + MDFloatLayout: + orientation: 'vertical' + md_bd_color: 1,1,1,1 + anchor_x: 'center' + anchor_y: 'center' + + MDBottomAppBar: + height: "62dp" + elevation: 10 + MDActionBottomAppBarButton: + icon: "home" + pos_hint:{'center_x':0.15, 'center_y': 0.5} + on_press: root.manager.current = 'home' + MDActionBottomAppBarButton: + icon: "tools" + pos_hint:{'center_x':0.38, 'center_y': 0.5} + on_press: root.manager.current = 'control_command' + MDActionBottomAppBarButton: + icon: "alert" + pos_hint:{'center_x':0.61, 'center_y': 0.5} + on_press: root.manager.current = 'history' + MDActionBottomAppBarButton: + icon: "chart-bell-curve-cumulative" + pos_hint:{'center_x':0.85, 'center_y': 0.5} + on_press: + root.manager.current = 'real_time_curve' + + MDIconButton: + icon: "arrow-left" + pos_hint: {'center_y': 0.95} + theme_text_color: "Custom" + text_color: rgba(26,24,58,255) + size_hint_x: None + width: dp(500) + on_touch_down: app.change_cursor(True) + on_touch_up: app.change_cursor(False) + on_release: + root.manager.transition.direction= 'right' + root.manager.current= "home" + app.on_press_back_arrow() + + MDLabel: + text: "Reading Chronicle" + font_name: "BPoppins" + font_size: "24sp" + size_hint_x: None + width: dp(400) + padding:"12dp" + pos_hint: {'center_x': 0.5,'center_y': 0.9} + color: rgba(0, 0, 59, 255) + + + MDLabel: + text: "Reflecting on Read and Returned" + 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) + + ScrollView: + size_hint: 1, None + height: self.parent.height - dp(150) + pos_hint: {'top':0.81} + MDList: + id : history_grid + padding: "1dp", "50dp", "12dp", "30dp" + spacing: "50dp" + +: + MDFloatLayout: + orientation: 'vertical' + md_bd_color: 1,1,1,1 + anchor_x: 'center' + anchor_y: 'center' + + MDBottomAppBar: + height: "62dp" + elevation: 10 + MDActionBottomAppBarButton: + icon: "home" + pos_hint:{'center_x':0.15, 'center_y': 0.5} + on_press: root.manager.current = 'home' + MDActionBottomAppBarButton: + icon: "tools" + pos_hint:{'center_x':0.38, 'center_y': 0.5} + on_press: root.manager.current = 'control_command' + MDActionBottomAppBarButton: + icon: "alert" + pos_hint:{'center_x':0.61, 'center_y': 0.5} + on_press: root.manager.current = 'history' + MDActionBottomAppBarButton: + icon: "chart-bell-curve-cumulative" + pos_hint:{'center_x':0.85, 'center_y': 0.5} + on_press: + root.manager.current = 'real_time_curve' + + MDIconButton: + icon: "arrow-left" + pos_hint: {'center_y': 0.95} + theme_text_color: "Custom" + text_color: rgba(26,24,58,255) + size_hint_x: None + width: dp(500) + on_touch_down: app.change_cursor(True) + on_touch_up: app.change_cursor(False) + on_release: + root.manager.transition.direction= 'right' + root.manager.current= "home" + app.on_press_back_arrow() + + MDLabel: + text: "Reading Chronicle" + font_name: "BPoppins" + font_size: "24sp" + size_hint_x: None + width: dp(400) + padding:"12dp" + pos_hint: {'center_x': 0.5,'center_y': 0.9} + color: rgba(0, 0, 59, 255) + + + MDLabel: + text: "Reflecting on Read and Returned" + 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) + + ScrollView: + size_hint: 1, None + height: self.parent.height - dp(150) + pos_hint: {'top':0.81} + MDList: + id : history_grid + padding: "1dp", "50dp", "12dp", "30dp" + spacing: "50dp" + +: + MDFloatLayout: + orientation: 'vertical' + md_bd_color: 1,1,1,1 + anchor_x: 'center' + anchor_y: 'center' + + MDBottomAppBar: + height: "62dp" + elevation: 10 + MDActionBottomAppBarButton: + icon: "home" + pos_hint:{'center_x':0.15, 'center_y': 0.5} + on_press: root.manager.current = 'home' + MDActionBottomAppBarButton: + icon: "tools" + pos_hint:{'center_x':0.38, 'center_y': 0.5} + on_press: root.manager.current = 'control_command' + MDActionBottomAppBarButton: + icon: "alert" + pos_hint:{'center_x':0.61, 'center_y': 0.5} + on_press: root.manager.current = 'history' + MDActionBottomAppBarButton: + icon: "chart-bell-curve-cumulative" + pos_hint:{'center_x':0.85, 'center_y': 0.5} + on_press: + root.manager.current = 'real_time_curve' + + MDIconButton: + icon: "arrow-left" + pos_hint: {'center_y': 0.95} + theme_text_color: "Custom" + text_color: rgba(26,24,58,255) + size_hint_x: None + width: dp(500) + on_touch_down: app.change_cursor(True) + on_touch_up: app.change_cursor(False) + on_release: + root.manager.transition.direction= 'right' + root.manager.current= "home" + app.on_press_back_arrow() + + MDLabel: + text: "Reading Chronicle" + font_name: "BPoppins" + font_size: "24sp" + size_hint_x: None + width: dp(400) + padding:"12dp" + pos_hint: {'center_x': 0.5,'center_y': 0.9} + color: rgba(0, 0, 59, 255) + + + MDLabel: + text: "Reflecting on Read and Returned" + 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) + + ScrollView: + size_hint: 1, None + height: self.parent.height - dp(150) + pos_hint: {'top':0.81} + MDList: + id : history_grid + padding: "1dp", "50dp", "12dp", "30dp" + spacing: "50dp" + +: + MDFloatLayout: + orientation: 'vertical' + md_bd_color: 1,1,1,1 + anchor_x: 'center' + anchor_y: 'center' + + MDBottomAppBar: + height: "62dp" + elevation: 10 + MDActionBottomAppBarButton: + icon: "home" + pos_hint:{'center_x':0.15, 'center_y': 0.5} + on_press: root.manager.current = 'home' + MDActionBottomAppBarButton: + icon: "tools" + pos_hint:{'center_x':0.38, 'center_y': 0.5} + on_press: root.manager.current = 'control_command' + MDActionBottomAppBarButton: + icon: "alert" + pos_hint:{'center_x':0.61, 'center_y': 0.5} + on_press: root.manager.current = 'history' + MDActionBottomAppBarButton: + icon: "chart-bell-curve-cumulative" + pos_hint:{'center_x':0.85, 'center_y': 0.5} + on_press: + root.manager.current = 'real_time_curve' + + MDIconButton: + icon: "arrow-left" + pos_hint: {'center_y': 0.95} + theme_text_color: "Custom" + text_color: rgba(26,24,58,255) + size_hint_x: None + width: dp(500) + on_touch_down: app.change_cursor(True) + on_touch_up: app.change_cursor(False) + on_release: + root.manager.transition.direction= 'right' + root.manager.current= "home" + app.on_press_back_arrow() + + MDLabel: + text: "Reading Chronicle" + font_name: "BPoppins" + font_size: "24sp" + size_hint_x: None + width: dp(400) + padding:"12dp" + pos_hint: {'center_x': 0.5,'center_y': 0.9} + color: rgba(0, 0, 59, 255) + + + MDLabel: + text: "Reflecting on Read and Returned" + 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) + + ScrollView: + size_hint: 1, None + height: self.parent.height - dp(150) + pos_hint: {'top':0.81} + MDList: + id : history_grid + padding: "1dp", "50dp", "12dp", "30dp" + spacing: "50dp" + +: + MDFloatLayout: + orientation: 'vertical' + md_bd_color: 1,1,1,1 + anchor_x: 'center' + anchor_y: 'center' + + MDBottomAppBar: + height: "62dp" + elevation: 10 + MDActionBottomAppBarButton: + icon: "home" + pos_hint:{'center_x':0.15, 'center_y': 0.5} + on_press: root.manager.current = 'home' + MDActionBottomAppBarButton: + icon: "tools" + pos_hint:{'center_x':0.38, 'center_y': 0.5} + on_press: root.manager.current = 'control_command' + MDActionBottomAppBarButton: + icon: "alert" + pos_hint:{'center_x':0.61, 'center_y': 0.5} + on_press: root.manager.current = 'history' + MDActionBottomAppBarButton: + icon: "chart-bell-curve-cumulative" + pos_hint:{'center_x':0.85, 'center_y': 0.5} + on_press: + root.manager.current = 'real_time_curve' + + MDIconButton: + icon: "arrow-left" + pos_hint: {'center_y': 0.95} + theme_text_color: "Custom" + text_color: rgba(26,24,58,255) + size_hint_x: None + width: dp(500) + on_touch_down: app.change_cursor(True) + on_touch_up: app.change_cursor(False) + on_release: + root.manager.transition.direction= 'right' + root.manager.current= "home" + app.on_press_back_arrow() + + MDLabel: + text: "Reading Chronicle" + font_name: "BPoppins" + font_size: "24sp" + size_hint_x: None + width: dp(400) + padding:"12dp" + pos_hint: {'center_x': 0.5,'center_y': 0.9} + color: rgba(0, 0, 59, 255) + + + MDLabel: + text: "Reflecting on Read and Returned" + 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) + + ScrollView: + size_hint: 1, None + height: self.parent.height - dp(150) + pos_hint: {'top':0.81} + MDList: + id : history_grid + padding: "1dp", "50dp", "12dp", "30dp" + spacing: "50dp" + +: + MDFloatLayout: + orientation: 'vertical' + md_bd_color: 1,1,1,1 + anchor_x: 'center' + anchor_y: 'center' + + MDBottomAppBar: + height: "62dp" + elevation: 10 + MDActionBottomAppBarButton: + icon: "home" + pos_hint:{'center_x':0.15, 'center_y': 0.5} + on_press: root.manager.current = 'home' + MDActionBottomAppBarButton: + icon: "tools" + pos_hint:{'center_x':0.38, 'center_y': 0.5} + on_press: root.manager.current = 'control_command' + MDActionBottomAppBarButton: + icon: "alert" + pos_hint:{'center_x':0.61, 'center_y': 0.5} + on_press: root.manager.current = 'history' + MDActionBottomAppBarButton: + icon: "chart-bell-curve-cumulative" + pos_hint:{'center_x':0.85, 'center_y': 0.5} + on_press: + root.manager.current = 'real_time_curve' + + MDIconButton: + icon: "arrow-left" + pos_hint: {'center_y': 0.95} + theme_text_color: "Custom" + text_color: rgba(26,24,58,255) + size_hint_x: None + width: dp(500) + on_touch_down: app.change_cursor(True) + on_touch_up: app.change_cursor(False) + on_release: + root.manager.transition.direction= 'right' + root.manager.current= "home" + app.on_press_back_arrow() + + MDLabel: + text: "Reading Chronicle" + font_name: "BPoppins" + font_size: "24sp" + size_hint_x: None + width: dp(400) + padding:"12dp" + pos_hint: {'center_x': 0.5,'center_y': 0.9} + color: rgba(0, 0, 59, 255) + + + MDLabel: + text: "Reflecting on Read and Returned" + 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) + + ScrollView: + size_hint: 1, None + height: self.parent.height - dp(150) + pos_hint: {'top':0.81} + MDList: + id : history_grid + padding: "1dp", "50dp", "12dp", "30dp" + spacing: "50dp" + +: + MDFloatLayout: + orientation: 'vertical' + md_bd_color: 1,1,1,1 + anchor_x: 'center' + anchor_y: 'center' + + MDBottomAppBar: + height: "62dp" + elevation: 10 + MDActionBottomAppBarButton: + icon: "home" + pos_hint:{'center_x':0.15, 'center_y': 0.5} + on_press: root.manager.current = 'home' + MDActionBottomAppBarButton: + icon: "tools" + pos_hint:{'center_x':0.38, 'center_y': 0.5} + on_press: root.manager.current = 'control_command' + MDActionBottomAppBarButton: + icon: "alert" + pos_hint:{'center_x':0.61, 'center_y': 0.5} + on_press: root.manager.current = 'history' + MDActionBottomAppBarButton: + icon: "chart-bell-curve-cumulative" + pos_hint:{'center_x':0.85, 'center_y': 0.5} + on_press: + root.manager.current = 'real_time_curve' + MDIconButton: + icon: "arrow-left" + pos_hint: {'center_y': 0.95} + theme_text_color: "Custom" + text_color: rgba(26,24,58,255) + size_hint_x: None + width: dp(500) + on_touch_down: app.change_cursor(True) + on_touch_up: app.change_cursor(False) + on_release: + root.manager.transition.direction= 'right' + root.manager.current= "home" + app.on_press_back_arrow() \ No newline at end of file diff --git a/main.py b/main.py index f933c3a..0665c1b 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,5 @@ -from kivy.properties import ObjectProperty, StringProperty +from kivy.properties import ObjectProperty, StringProperty, ListProperty from datetime import datetime, timedelta from kivy.core.text import LabelBase from kivy.metrics import dp @@ -26,6 +26,16 @@ 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 + +from modbus_tk.modbus_tcp import TcpMaster +import modbus_tk.defines as cst +import socket + +from random import randint from kivymd.theming import ThemeManager LabelBase.register(name="MPoppins", fn_regular="fonts/Chinese/msyh.ttf") @@ -41,51 +51,58 @@ def get_books(): 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) + class SignUpScreen(Screen): signup = ObjectProperty(None) - class ForgetPassScreen(Screen): forget_Password = ObjectProperty(None) - class OtpScreen(Screen): otp = ObjectProperty(None) - class ResetPassScreen(Screen): reset_pass = ObjectProperty(None) - -class HomeScreen(Screen): - home = ObjectProperty(None) - -class ProfileScreen(Screen): - profile = ObjectProperty(None) - -class ProfileEditScreen(Screen): - profile_edit = ObjectProperty(None) - class SearchBookScreen(Screen): search_book = ObjectProperty(None) - class NotificationScreen(Screen): notifications = ObjectProperty(None) - class RecommendScreen(Screen): recommendation = ObjectProperty(None) - class BorrowBookScreen(Screen): borrow_book = ObjectProperty(None) - class ReturnBookScreen(Screen): return_book = ObjectProperty(None) - class RenewBookScreen(Screen): renew_book = ObjectProperty(None) -class HistoryScreen(Screen): - history = ObjectProperty(None) + + # Window.size = (dp(360), dp(680)) @@ -148,6 +165,11 @@ class app(MDApp): self.password = None self.username = None + self.modbus_master = None # 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] @@ -168,21 +190,36 @@ class app(MDApp): 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")) + screen_manager.add_widget(SignUpScreen(name="signup")) screen_manager.add_widget(ForgetPassScreen(name="forgot_pass")) screen_manager.add_widget(OtpScreen(name="otp")) screen_manager.add_widget(ResetPassScreen(name="reset_pass")) - screen_manager.add_widget(ProfileScreen(name="profile")) - screen_manager.add_widget(ProfileEditScreen(name="profile_edit")) screen_manager.add_widget(NotificationScreen(name="notification")) screen_manager.add_widget(SearchBookScreen(name="searchBook")) screen_manager.add_widget(RecommendScreen(name="recommend")) screen_manager.add_widget(BorrowBookScreen(name="borrow_book")) screen_manager.add_widget(ReturnBookScreen(name="return_book")) screen_manager.add_widget(RenewBookScreen(name="renew_book")) - screen_manager.add_widget(HistoryScreen(name="history")) + Clock.schedule_once(self.update_wifi_status, 2) + + + # Clock.schedule_interval(self.update_register_display, 1) + return screen_manager #############################################ALL INPUT TEXT############################################################ @@ -232,21 +269,21 @@ class app(MDApp): self.d4 = otp_screen.ids.d4 # 从根窗口中获取名为"signup"的屏幕(注册界面) - signup_screen = self.root.get_screen("signup") + # signup_screen = self.root.get_screen("signup") # 通过界面ID获取注册界面中的用户名输入框组件 - self.user_name = signup_screen.ids.signup_name + # self.user_name = signup_screen.ids.signup_name # 通过界面ID获取注册界面中的PRN(可能是学号/身份标识)输入框组件 - self.user_prn = signup_screen.ids.signup_prn + # self.user_prn = signup_screen.ids.signup_prn # 通过界面ID获取注册界面中的邮箱输入框组件 - self.user_email = signup_screen.ids.signup_email + # self.user_email = signup_screen.ids.signup_email # 通过界面ID获取注册界面中的手机号输入框组件 - self.user_no = signup_screen.ids.signup_no + # self.user_no = signup_screen.ids.signup_no # 通过界面ID获取注册界面中的密码输入框组件 - self.user_pass = signup_screen.ids.signup_pass + # self.user_pass = signup_screen.ids.signup_pass # 通过界面ID获取注册界面中的所属部门/专业选择组件 - self.signup_branch = signup_screen.ids.signup_branch + # self.signup_branch = signup_screen.ids.signup_branch # 通过界面ID获取注册界面中的年级/学期选择组件 - self.signup_sem = signup_screen.ids.signup_sem + # self.signup_sem = signup_screen.ids.signup_sem # 从根窗口中获取名为"profile"的屏幕(个人资料界面) profile_screen = self.root.get_screen("profile") @@ -314,7 +351,76 @@ class app(MDApp): # 通过界面ID获取推荐界面中的推荐信息标签组件 self.rec_label = self.recommend_screen.ids.rec_label - #############################################@Frequently used functions################################################## + self.root.bind(current=self.on_screen_changed) + self.register_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 + + 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): + # """更新原标签的显示内容""" + # # 仅在目标屏幕时更新 + # if self.root.current != "real_time_curve": + # return + # # 读取值并更新到原标签 + # value = self.read_modbus_register() + # 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): + """写入寄存器值""" + if not self.modbus_master: + pass + try: + self.modbus_master.execute(1, cst.WRITE_SINGLE_REGISTER, 0, value) + return "修改成功" + except Exception as e: + return f"修改失败: {e}" + + 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) + # 若成功,立即刷新原标签显示 + if "成功" in result: + self.update_register_display(0) + except ValueError: + self.show_dialog("错误", "请输入有效整数") + + def show_dialog(self, title, message): + self.dialog2(title, message) +#############################################@Frequently used functions################################################## @staticmethod def change_cursor(is_enter): @@ -436,61 +542,62 @@ class app(MDApp): 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 read_modbus_register(self): + """读取Modbus寄存器值并更新界面显示""" + if not self.modbus_master: + pass + + try: + # 读取寄存器(1号从机,保持寄存器,地址0,长度1) + result = self.modbus_master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 1) + # 结果是元组,取第一个值 + return str(result[0]) + except Exception as e: + pass + + def update_register_display(self, dt): + """定时更新寄存器值显示""" + register_value = self.read_modbus_register() + # 获取显示标签并更新文本 + 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}" + ###################################LoginPageWork-Start################################################# - # # login Verification function "verify" - # def verify(self, obj): - # status = False - # if self.username.text == "" or self.password.text == "": - # check = "请输入账户和密码" - # return self.dialog1(check) - # else: - # name = "" - # with open('data/Users.csv', "r", encoding="utf-8") as file: - # csv_reader = csv.reader(file, delimiter=",") - # for line in csv_reader: - # try: - # if not obj: - # a = (line[1] == self.username.text or line[2] == self.username.text) - # else: - # a = (line[1] == self.edit_prn.text or line[2] == self.edit_email.text) - # if a and line[4] == self.password.text: - # status = True - # name = line[0] - # prn = line[1] - # email = line[2] - # number = line[3] - # branch = line[5] - # semester = line[6] - # break - # except IndexError: - # pass - # except Exception as e: - # print(e) - - # if status: - # if not obj: - # check = "Login Successful" + "\nHello! " + name - # else: - # check = "Profile Updated Successfully!" - # self.secure_profile() - # self.root.current = "home" - # self.user.text = f"""[b]Hey! {name}[/b]""" - # self.profile_name.text = self.edit_name.text = name - # self.profile_email.text = self.edit_email.text = email - # self.profile_prn.text = self.edit_prn.text = prn - # self.profile_number.text = self.edit_number.text = number - # self.profile_semester.text = self.edit_semester.text = semester - # self.profile_branch.text = self.edit_branch.text = branch - - # else: - # check = "Login Failed!. " + "Enter correct username and password." - # self.dialog1(check) def update_wifi_status(self, dt): self.check_wifi() Clock.schedule_once(self.update_wifi_status, 1) # 5秒刷新一次 @@ -558,21 +665,23 @@ class app(MDApp): else: wifi_id = "zhizhan-2" # 非 Android 用模拟 WiFi except Exception as e: - self.dialog1(f"获取WiFi信息失败:{e}") + self.dialog1(f"获取WiFi信息失败:{e}") return try: with open("data/Users.csv", "r", encoding="utf-8") as file: csv_reader = csv.reader(file) for line in csv_reader: - # 确保至少有7列数据 - if len(line) < 7: + + if len(line) < 8: continue - csv_ssid = line[7].strip().lower() if len(line) > 7 else "" + # 假设SSID存储在第8列(索引7) + csv_ssid = line[7].strip().lower() + # 更精确匹配SSID,且忽略大小写 if wifi_id == csv_ssid or wifi_id in map(str.lower, line): - name, prn, email, number, password, branch, semester = line[:7] + name, prn, email, number, password, branch, semester,csv_ssid = line[:8] self.root.current = "home" self.user.text = f"[b]Hey! {name}[/b]" @@ -583,35 +692,80 @@ class app(MDApp): self.profile_semester.text = self.edit_semester.text = semester self.profile_branch.text = self.edit_branch.text = branch - self.dialog1(f"欢迎你,{name} wifi认证成功") + self.connect_modbus() + self.dialog1(f"欢迎你,{name}!\n认证成功!") + return except Exception as e: self.dialog1(f"读取用户信息失败:{e}") return - self.dialog1("当前WiFi认证失败,请检查网络或退出") + self.dialog1("认证失败,请检查网络或确保手机权限打开定位和连接到目标WiFi") + # 添加Modbus连接函数 + def connect_modbus(self): + try: + # 从CSV文件读取Modbus配置 + modbus_ip = None + modbus_port = 502 # 默认端口 + + # 获取当前连接的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" # 非Android环境模拟WiFi + + # 读取CSV文件查找匹配的Modbus配置 + with open("data/Users.csv", "r", encoding="utf-8") as file: + csv_reader = csv.reader(file) + headers = next(csv_reader) # 获取表头 + + for line in csv_reader: + if len(line) < 10: # 确保有足够的字段 + continue + + # 匹配当前连接的WiFi SSID + csv_ssid = line[7].strip().lower() + if current_wifi_id == csv_ssid or current_wifi_id in map(str.lower, line): + modbus_ip = line[8] + modbus_port = int(line[9]) if line[9] else 502 + break # 找到匹配项则退出循环 + + if not modbus_ip: + # self.dialog1("未找到与当前WiFi匹配的Modbus配置") + return + # 断开现有连接(如果存在) + if hasattr(self, 'modbus_master') and self.modbus_master: + self.modbus_master.close() + + # 创建新连接 + self.modbus_master = TcpMaster(host=modbus_ip, port=modbus_port) + self.modbus_master.set_timeout(5.0) # 设置超时时间 + + # 测试连接(读取一个保持寄存器) + self.modbus_master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 1) + print(f"Modbus连接成功\nIP: {modbus_ip}\n端口: {modbus_port}") + + except FileNotFoundError: + self.dialog1("配置文件user.csv未找到") + except socket.error as e: + self.dialog1(f"Modbus连接失败: 网络错误\n{e}") + self.modbus_master = None + except Exception as e: + self.dialog1(f"Modbus连接失败: {e}") + self.modbus_master = None - click_count = 0 - def login_mode(self, username_text, button_text): - self.click_count += 1 - if self.click_count % 2 == 0: - username_text.hint_text = "Enter PRN" - button_text.text = "VIT Email Login" - username_text.icon_right = "dialpad" - username_text.helper_text = "PRN of 8 digits starting with 1 2 ......only*" - username_text.max_text_length = 8 - else: - username_text.hint_text = "Enter Email" - username_text.icon_right = "email-arrow-left" - button_text.text = "VIT PRN Login" - username_text.helper_text = "enter email ID of vit.edu only*" - username_text.max_text_length = 50 ###############################################SIGNUP Page Functions##################################################### # signup Verification function "check_signup" - def check_signup(self, name, prn, email, num, password, branch, sem): + def check_signup(self, name, prn, email, num, password, branch, sem, 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) @@ -630,7 +784,6 @@ class app(MDApp): if line[2] == email: status = "email" break - else: status = False except IndexError: @@ -647,6 +800,9 @@ class app(MDApp): 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) @@ -1226,14 +1382,6 @@ class app(MDApp): self.book_pos.text = "Please check the Spell!" -# LabelBase.register(name="MPoppins", fn_regular="fonts/Poppins/Poppins-Medium.ttf") -# LabelBase.register(name="BPoppins", fn_regular="fonts/Poppins/Poppins-SemiBold.ttf") -# LabelBase.register(name="RRubik", fn_regular="fonts/Rubik_Vinyl/RubikVinyl-Regular.ttf") -# LabelBase.register(name="RCro", fn_regular="fonts/Croissant_One/CroissantOne-Regular.ttf") -# LabelBase.register(name="RPac", fn_regular="fonts/Pacifico/Pacifico-Regular.ttf") - - - if __name__ == '__main__': app().run() diff --git a/menu_mine.py b/menu_mine.py deleted file mode 100644 index 054c7d2..0000000 --- a/menu_mine.py +++ /dev/null @@ -1,2536 +0,0 @@ -from device_conf import class_comm_device_config -import comm_remap as remap -import menu_utils as uitls -from enum import Enum -from datetime import datetime -import time -import menu_utils as utils -import json -import re -from enum import Enum -from comm_modbus_device import class_modbus_comm_device - -now_time = datetime.now() -current_time = now_time.strftime("(%y/%m/%d)") -VERSION_DATE = current_time - -class StrInfo(Enum): - STR_MAX_VALUE = 0, #"最大值" - STR_MIN_VALUE = 1, #"最小值" - STR_SET_VALUE = 2, #"设定值" - STR_VALUE_EXCEED = 3, #"设定值越界" - STR_ZERO_PHASE = 4, #"有功相位" - STR_INPUT_PASSWORD = 5, #"请输入系统密码 - STR_SYSTEM_PASSWORD = 6, #"系统密码" - STR_PASSWORD_ERR = 7, #"密码错误" - STR_SHORT_PHASE_MODIFY =8, #"短路倍数\n恢复缺省" - STR_SWITCH_TYPE_MODIFY =9, #"漏电延时\n恢复缺省" - STR_SOFT_VERSION =10, #"软件版本" - STR_NO_RECORD =11, #"无记录" - STR_ENTER_TO_CLEAR =12, #"确定清除" - STR_ESC_TO_CANCEL =13, #"ESC取消" - STR_CLEAR_FINISH =14, #"清除成功" - STR_ESC_TO_EXIT =15, #"ESC退出 - STR_INPUT_NEW_PASSWORD =16, #"请设置新密码" - STR_NOT_POSSIBLE_TO_MODIFY =17, #"不可修改" - STR_CAPACITOR_MEASURE =18, #"电容检测 - STR_CAPACITOR_EQUAL =19, #"电容" - STR_LEEKAGE_MEASURE =20, #"检测中.." - STR_TEST_ACTIVE =21, #"测试状态 - STR_POWER_ON=22, #"合闸" - STR_POWER_OFF=23, #"分闸" - STR_FAIL=24, #"失效" - STR_NORMAL=25, #"正常" - STR_MEASURE_CURRENT=26, #"实测电流" - STR_RATE_CURRENT=27, #"额定电流" - STR_ANGLE=28, #"角度" - STR_AVERAGE_CURRENT=29, #"平均电流" - STR_MAX_CURRENT=30, #"最大电流 - STR_LOW_VOLTAGE_RATE=31, #"欠压值 - STR_MEASURE_VOLTAGE=32, #"实测电压" - STR_ZERO_CURRENT=33, #"零序电流" - STR_ZERO_VOLTAGE=34, #"零序电压" - STR_RECORD=35, #"记录" - STR_LEEAKGE_LOCK_VALUE=36, #"闭锁设定值" - STR_LEEAKGE_ACTIVE_VALUE=37, #"动作设定值" - STR_MEASURE_RESISTOR=38, #"电阻测量值" - STR_FRONT_CIRCUIT=39, #"前机" - STR_NEXT_CIRCUIT=40, #"后机" - STR_RATE_VOLTAGE=41, #"额定电压" - STR_PARA_MODIFY_ERROR=42, #"参数修改失败" - STR_LEEKAGE_RES_FINISH=43, #"闭锁电阻检测完" - STR_LEEKAGE_RES_MEASURE=44, #"闭锁电阻检测中" - STR_SFJ_MONITOR=45, #"双风机磁力监控" - STR_CL_MONITOR=46, #"磁力监控系统" - STR_CL_DB_MONITOR=47, #"双回路磁力监控" - STR_YB_MONITOR=48, #"移变低压侧" - STR_KUI_DIAN_MONITOR=49, #"馈电开关监控" - STR_TYPE=50, #"类型:" - STR_TOP_SWITCH=51, #"总开关" - STR_BOTTOM_SWITCH=52, #"分开关" - STR_COS_V=53, #"COS(ΦaΦbΦc)" - STR_POWER_VI=54, #"有功功率" - STR_POWER_VI_T=55, #"电量" - STR_FRONT_POWER_ON=56, #"前机合" - STR_NEXT_POWER_ON=57, #"后机合" - STR_FRONT_POWER_OFF=58, #"前机分" - STR_NEXT_POWER_OFF=59, #"后机分" - STR_FRONT_RESISTOR=60, #"前机电阻:" - STR_NEXT_RESISTOR=61, #"后机电阻:" - STR_WORK_MODE=62, #"模式:" - STR_LEEKAGE_RES=63, #"漏电电阻" - STR_REVERSE_VOLTAGE=64, #"反电动势\n注意安全" - STR_LIGHT=65, #"照明" - STR_SIGNAL=66, #"信号" - STR_SWITCH_STATUS=67, #"开关状态" - STR_POWER_ON_COUNTS=68, #"合闸次数" - STR_SETTING=69, #"设定值" - STR_POW_U=70, #"无功功率" - STR_TEST_FAIL=71, #"测试不正确" - STR_LEAKAGE_TEST_FAIL=72, #"漏电测试不正确" - STR_DETECT_FAIL_WHEN_POWER_ON=73, #"合闸时不能检测" - STR_LINK=74, #"联机系统" - STR_SINGLE=75, #"单机系统" - STR_STATUS=76, #"状态" - STR_MAIN_FIRST=77, #"主机优先" - STR_MAIN_BAK_SAME=78, #"主辅对等" - STR_MAIN_BAK_SWITCH=79, #"主辅轮动" - STR_SWITCH_DISABLE=80, #"局扇模式" - STR_MAIN=81, #"主机" - STR_BACKUP=82, #"备机" - STR_SINGLE_CIRCUIT_FRONT=83, #"单前机" - STR_SINGLE_CIRCUIT_NEXT=84, #"单后机" - STR_DOUBLE_CIRCUIT=85, #"双回路" - STR_WATER_PUMP_ON=86, #"水泵已开阀" - STR_WATER_PUMP_OFF=87, #"水泵已关阀" - STR_SWITCH_FAIL=88, #"粘连" - STR_SWITCH_THROUGH_2=89, #"击穿" - STR_GB_MONITOR=90, #"高压真空配电装置" - STR_GB_PROTECT_SYSTEM=91, #"综合保护监控系统" - STR_YBGY_MONITOR=92, #"移变高压侧" - STR_ERROR=93, #"故障" - STR_TEMPERATURE=94, #"温度" - STR_NEXT_CURRENT=95, #"后机电流" - STR_FRONT_CURRENT=96, #"前机电流" - STR_FJ_WS_LOCK=97, #"风机处瓦斯闭锁" - STR_GZM_WS_LOCK=98, #"工作面瓦斯闭锁" - STR_CURRENT=99, #"电流" - STR_VOLTAGE=100, #"电压" - STR_MONITOR_RES=101, #"监视电阻" - STR_SWITCH_THROUGH_SIMPLE=102, #"击穿" - STR_LINK_FAIL=103, #"联机失败" - STR_RES_OFF=104, #"漏电临界值" - STR_ANOTHER_REPAIR=105, #"另台维修请勿停机" - STR_WS_INTENSITY=106, #"瓦斯浓度" - STR_HIGH_VOLT=107, #"高压" - STR_AUTO=108, #"自动" - STR_MANUAL=109, #"手动" - STR_FREQUENCY=110, #"频率" - STR_FWD_ON=111, #正向启动 - STR_RVS_ON=112, #反向启动 - STR_TEMPERATURE_UNIT=113, #温度单位 - STR_POWER_LOSS=114, - STR_CALIBRATE_SUCCESS=115, #标定成功 - STR_ISOLATE_RES=116, #绝缘电阻 - STR_WATER_MONITOR=117, #水位控制排水监控系统 - STR_SWTICH_PROTECTOR=118, #ZDB-200电动机保护器 - STR_INDEPENDENT=119, #独立模式 - STR_DEPENDENT=120, #联动模式 - STR_OUT_POSITION=121, - STR_IN_POSITION=122, - STR_QUIT_IN_POSITION=123, - STR_RUN_DATA=124, - STR_WATER_MODE=125, - STR_INV_MODE=126, - STR_ISOLATE_RESISTOR_LOW=127, - STR_SWITCH=128, - STR_DIDAO=129, - STR_REMOTE=130, - STR_LOCAL=131, - STR_ONE_KEY_LOCK=132, - STR_COMM_FAIL=133, - -class Alarm(Enum): - ERR_NONE = 0, - ERR_CREEPAGE_LOCK = 1, #漏电报警 - ERR_VOLTAGE_LOW = 2, #欠压报警 - ERR_OVER_CURRENT = 3, #过流保护 - ERR_SHORT_CURRENT = 4, #短路保护 - ERR_CREEPAGE_SELECT = 5, #选漏 - ERR_UNBANLANCE_CURRENT = 6, #三相不平衡 - ERR_FLASH_FAIL = 7, #FLASH无法写入 - ERR_CREEPAGE_ACTIVE = 8, #漏电动作 - ERR_BREAK_PHASE = 9, #断相保护动作 - ERR_VOLTAGE_BREAK_PHASE = 10, #电压断相 - ERR_GAS_LOCK = 11, #瓦斯闭锁 - ERR_WIND_MOTOR_LOCK = 12, #风电闭锁 - ERR_VOLTAGE_OVER = 13, #过压报警 - ERR_SHORT_PHASE = 14, #相敏短路 - ERR_WATCH_DOG = 15, #看门狗保房 - ERR_SWITCH_FAIL = 16, #开关粘轿 - ERR_SWITCH_THROUGH = 17, #开关击? - ERR_SWITCH_ON_FAIL = 18, #开关合闸失? - ERR_COMM_FAIL = 19, #通讯故障 - ERR_CREEPAGE_SELECT2 = 20, #选择性报? - ERR_TEMP_IO_HIGH = 21, #IO口温度过驿 - ERR_SHORT_CURRENT_SIGNAL = 22, #信号电流短路 - ERR_REMOTE_OFF = 23, #远方分励 - ERR_REPAIR = 24, #维修状? - ERR_TEMP_ALARM = 25, #温度报警 - ERR_QUICK_CREEPAGE_ACT = 26, #快速漏电动仿 - ERR_GB_LEEK_SHORT = 27, #高爆绝缘短路 - ERR_GB_LEEK_BREAK = 28, #高爆绝缘断路 - ERR_YB_LOW_VOLTAGE_FAIL = 29, #移变低压侧失? - ERR_YB_LOW_VOLTAGE_UNREADY = 30, #移变低压侧未准备? - ERR_WS_FREQ_FAIL = 31, #瓦斯浓度超标 - ERR_HIGH_LOW_LOCK = 32, #高低压联钿 - ERR_MOTOR_ROTATE_LOCK = 33, #电机堵转 - ERR_FIX_TIME_OVER_CURRENT = 34, #定时限过泿 - ERR_FIX_TIME_SHORT_CURRENT = 35, #定时限短? - ERR_PHASE_ERROR = 36, #相序故障 - ERR_UNDER_LOAD = 37, #欠载保护 - ERR_PHASE_UNMATCH = 38, #互感器反? - ERR_EXTERNAL_ALARM = 39, #外部故障 - ERR_SENSOR_LOSS = 40, #水位传感器未? - ERR_ROTOR_SLOW = 41, - ERR_ROTOR_LOCK = 42, - ERR_POWER_LOSS = 43, #系统断电 - ERR_RSV1 = 44, - ERR_RSV2 = 45, - ERR_RSV3 = 46, - ERR_RSV4 = 47, - ERR_RSV5 = 48, - ERR_RSV6 = 49, - ERR_RSV7 = 50, - ERR_USER_ALARM1 = 51, #50,用户自定义故阿 - ERR_USER_ALARM2 = 52, #51,用户自定义故阿 - ERR_USER_ALARM3 = 53, #52,用户自定义故阿 - ERR_USER_ALARM4 = 54, #53,用户自定义故阿 - ERR_GB_LIGHT_THREAD_SON_LOSS = 55, - ERR_GB_LIGHT_THREAD_BROTHER_LOSS = 56, - ERR_GB_LIGHT_MODULE_LOSS = 57, - ERR_GB_FORCE_LEEK_OFF = 58, - ERR_GB_FORCE_SHORT_OFF = 59, - ERR_GB_CREEPAGE_SELECT = 60, #选择性报警 - ERR_SWITCH_OUT_POSITION = 61, - ERR_DZM_CREEPAGE_ACTIVE = 62, - ERR_OIL_PRESSURE_SENSOR_FAIL = 63, - ERR_FREQ_SENSOR_EXCEED = 64, - ERR_FREQ_SENSOR_FAIL = 65, - ERR_ANALOG_SENSOR_EXCEED = 66, - ERR_ANALOG_SENSOR_FAIL = 67, - ERR_VOLTAGE_LOSS = 68, - ERR_SPEED_LOSS = 69, - ERR_GB_ZERO_VOLT_OVER = 70, #零序过压 - ERR_PT_BREAK = 71, - ERR_CT_BREAK = 72, - ERR_ZERO_OVER_VOLTAGE = 73, - ERR_ZERO_OVER_CURRENT = 74, - ERR_GAS_WARNING = 75, - ERR_TEMP_WARNING = 76, - ERR_COMM_LOSS = 77, - ERR_CAR_FAIL = 78, - ERR_WATER_LOW = 79, - ERR_SWITCH_DIDAO_IN_POSITION = 80, - ERR_SWITCH_DIDAO_MID_POSITION = 81, - ERR_GB_CREEPAGE_SELECT_5 = 82, #5次谐波选漏 - ERR_FLUX_LOCK = 83, - ERR_GLOBAL_OIL_TEMP_LOCK = 84, - ERR_GLOBAL_WATER_PRESSURE_LOCK = 85, - ERR_GLOBAL_WATER_LEVEL_LOCK = 86, - ERR_GLOBAL_CURRENT_SENSOR_LOSS = 87, - ERR_GLOBAL_GAS_PERCENTAGE_LOCK = 88, - ERR_GLOBAL_GAS_SENSOR_LOSS = 89, - ERR_MEASURE_OVER_CURRENT = 90, #测量回路过流保护 - ERR_CREAPGE_BREAK = 91, - ERR_REMOTE_CREAPGE_TEST_FAIL = 92, - ERR_REMOTE_CREAPGE_TEST_SUCCESS = 93, - - - -class Alias(Enum): - alias_alarm = 0, - alias_str = 1, - alias_company = 2, - alias_bool = 3, - alias_voltage = 4, - alias_parity = 5, - alias_baud = 6, - alias_input = 7, - alias_onoff = 8, - alias_test = 9, - alias_can_baud = 10, - alias_measure_v = 11, - alias_switch_type = 12, - alias_work_mode = 13, - alias_us_phase = 14, - alias_sensor = 15, - alias_table = 16, - alias_remote = 17, - alias_current = 18, - alias_eth = 19, - alias_lcd = 20, - alias_dev = 21, - alias_fyj = 22, - alias_alarm_type = 23, - alias_car_position = 24, - -class Menu(Enum): - menu_current = 0, - menu_test = 1, - -alias_table = [ - {Alias.alias_alarm: {Alarm.ERR_NONE: "无故障", - Alarm.ERR_CREEPAGE_LOCK: "漏电闭锁", - Alarm.ERR_VOLTAGE_LOW: "欠压", - Alarm.ERR_OVER_CURRENT : "过流保护", #过流保护 - Alarm.ERR_SHORT_CURRENT : "短路保护", #短路保护 - Alarm.ERR_CREEPAGE_SELECT : "选漏", #选漏 - Alarm.ERR_UNBANLANCE_CURRENT : "三相不平衡", #三相不平衡报? - Alarm.ERR_FLASH_FAIL : "FLASH无法写入", #FLASH无法写入 - Alarm.ERR_CREEPAGE_ACTIVE : "漏电动作", #漏电动作 - Alarm.ERR_BREAK_PHASE : "电流断相", #断相保护动作 - Alarm.ERR_VOLTAGE_BREAK_PHASE : "电压断相", #电压断相 - Alarm.ERR_GAS_LOCK : "瓦斯闭锁", #瓦斯闭锁 - Alarm.ERR_WIND_MOTOR_LOCK : "风电闭锁", #风电闭锁 - Alarm.ERR_VOLTAGE_OVER : "过压", #过压报警 - Alarm.ERR_SHORT_PHASE : "相敏短路", #相敏短路 - Alarm.ERR_WATCH_DOG : "看门狗重启", #看门狗保房 - Alarm.ERR_SWITCH_FAIL : "真空管粘连", #真空管粘连 - Alarm.ERR_SWITCH_THROUGH : "真空管击穿", #真空管击穿 - Alarm.ERR_SWITCH_ON_FAIL : "合闸失败", #合闸失败 - Alarm.ERR_COMM_FAIL : "通讯失败", #通讯失败 - Alarm.ERR_CREEPAGE_SELECT2 : "选 漏", #选 漏 - Alarm.ERR_TEMP_IO_HIGH : "温度过高", #温度过高 - Alarm.ERR_SHORT_CURRENT_SIGNAL : "信号电流短路", #信号电流短路 - Alarm.ERR_REMOTE_OFF : "远方分励", #远方分励 - Alarm.ERR_REPAIR : "维修状态", #维修状态 - Alarm.ERR_TEMP_ALARM : "温度报警", #温度报警 - Alarm.ERR_QUICK_CREEPAGE_ACT : "漏电 动作", #快速漏电 动作 - Alarm.ERR_GB_LEEK_SHORT : "绝缘短路", #绝缘短路 - Alarm.ERR_GB_LEEK_BREAK : "绝缘断路", #绝缘断路 - Alarm.ERR_YB_LOW_VOLTAGE_FAIL : "低压侧故障", #低压侧故障 - Alarm.ERR_YB_LOW_VOLTAGE_UNREADY : "低压侧未准备好", #低压侧未准备好 - Alarm.ERR_WS_FREQ_FAIL : "瓦斯浓度超标", #瓦斯浓度超标 - Alarm.ERR_HIGH_LOW_LOCK : "高低压联锁", #高低压联锁 - Alarm.ERR_MOTOR_ROTATE_LOCK : "电机堵转", #电机堵转 - Alarm.ERR_FIX_TIME_OVER_CURRENT : "定时限过流", #定时限过流 - Alarm.ERR_FIX_TIME_SHORT_CURRENT : "定时限短路", #定时限短路? - Alarm.ERR_PHASE_ERROR : "相序故障", #相序故障 - Alarm.ERR_UNDER_LOAD : "欠载保护", #欠载保护 - Alarm.ERR_EXTERNAL_ALARM : "外部故障", #外部故障 - Alarm.ERR_POWER_LOSS : "系统断电", #系统断电 - Alarm.ERR_USER_ALARM1 : "触头温度超标", #用户自定义故阿 - Alarm.ERR_USER_ALARM2 : "触头温度超标", #用户自定义故阿 - Alarm.ERR_GB_LIGHT_THREAD_SON_LOSS : "光纤子节点丢失", - Alarm.ERR_GB_LIGHT_THREAD_BROTHER_LOSS : "光纤兄弟节点丢失", - Alarm.ERR_GB_LIGHT_MODULE_LOSS : "无光纤模块", - Alarm.ERR_GB_FORCE_LEEK_OFF : "光纤漏电越级跳", - Alarm.ERR_GB_FORCE_SHORT_OFF : "光纤短路越级跳", - Alarm.ERR_GB_CREEPAGE_SELECT : "漏电", #选择性报警 - Alarm.ERR_SWITCH_OUT_POSITION : "开关未推到位", - Alarm.ERR_DZM_CREEPAGE_ACTIVE : "漏电动作", - Alarm.ERR_OIL_PRESSURE_SENSOR_FAIL : "油压传感器未接入", - Alarm.ERR_FREQ_SENSOR_EXCEED : "频率传感器超限", - Alarm.ERR_FREQ_SENSOR_FAIL : "频率传感器未接入", - Alarm.ERR_ANALOG_SENSOR_EXCEED : "模拟量传感器超限", - Alarm.ERR_ANALOG_SENSOR_FAIL : "模拟量传感器未接入", - Alarm.ERR_VOLTAGE_LOSS : "失压故障", - Alarm.ERR_SPEED_LOSS : "失速故障", - Alarm.ERR_GB_ZERO_VOLT_OVER : "零序过压", - Alarm.ERR_PT_BREAK : "PT断线", - Alarm.ERR_CT_BREAK : "CT断线", - Alarm.ERR_ZERO_OVER_VOLTAGE : "零序过压", - Alarm.ERR_ZERO_OVER_CURRENT : "零序过流", - Alarm.ERR_GAS_WARNING : "轻瓦斯告警", - Alarm.ERR_TEMP_WARNING : "温度异常", - Alarm.ERR_COMM_LOSS : "通讯中断", - Alarm.ERR_CAR_FAIL : "手车控制器故障", - Alarm.ERR_WATER_LOW : "循环泵无水故障", - Alarm.ERR_SWITCH_DIDAO_IN_POSITION: "地刀合闸保护中", - Alarm.ERR_SWITCH_DIDAO_MID_POSITION: "地刀未到位", - Alarm.ERR_GB_CREEPAGE_SELECT_5: "5次谐波选漏", - Alarm.ERR_FLUX_LOCK: "流量闭锁", - Alarm.ERR_GLOBAL_OIL_TEMP_LOCK: "油温闭锁", - Alarm.ERR_GLOBAL_WATER_PRESSURE_LOCK: "水压闭锁", - Alarm.ERR_GLOBAL_WATER_LEVEL_LOCK: "液位闭锁", - Alarm.ERR_GLOBAL_CURRENT_SENSOR_LOSS: "互感器未接入", - Alarm.ERR_GLOBAL_GAS_PERCENTAGE_LOCK: "瓦斯浓度闭锁", - Alarm.ERR_GLOBAL_GAS_SENSOR_LOSS: "瓦斯断线", - Alarm.ERR_MEASURE_OVER_CURRENT: "测量回路过流", - Alarm.ERR_CREAPGE_BREAK: "接地开路", - Alarm.ERR_REMOTE_CREAPGE_TEST_FAIL: "漏电测试失败", - Alarm.ERR_REMOTE_CREAPGE_TEST_SUCCESS: "漏电测试成功", - } - }, - - {"alias_str" : { StrInfo.STR_MAX_VALUE :"最大值", - StrInfo.STR_MIN_VALUE :"最小值", - StrInfo.STR_SET_VALUE :"设定值", - StrInfo.STR_VALUE_EXCEED :"设定值越界", - StrInfo.STR_ZERO_PHASE :"有功相位", - StrInfo.STR_INPUT_PASSWORD :"请输入系统密码", - StrInfo.STR_SYSTEM_PASSWORD :"系统密码", - StrInfo.STR_PASSWORD_ERR :"密码错误", - StrInfo.STR_SHORT_PHASE_MODIFY :"短路倍数\n恢复缺省", - StrInfo.STR_SWITCH_TYPE_MODIFY :"漏电延时\n恢复缺省", - StrInfo.STR_SOFT_VERSION:"软件版本", - StrInfo.STR_NO_RECORD :"无记录", - StrInfo.STR_ENTER_TO_CLEAR:"确定清除", - StrInfo.STR_ESC_TO_CANCEL:"ESC取消", - StrInfo.STR_CLEAR_FINISH :"清除成功", - StrInfo.STR_ESC_TO_EXIT :"ESC退出", - StrInfo.STR_INPUT_NEW_PASSWORD :"请设置新密码", - StrInfo.STR_NOT_POSSIBLE_TO_MODIFY :"不可修改", - StrInfo.STR_CAPACITOR_MEASURE :"电容检测", - StrInfo.STR_CAPACITOR_EQUAL :"电容", - StrInfo.STR_LEEKAGE_MEASURE :"检测中..", - StrInfo.STR_TEST_ACTIVE :"测试状态", - StrInfo.STR_POWER_ON :"合闸", - StrInfo.STR_POWER_OFF :"分闸", - StrInfo.STR_FAIL :"失效", - StrInfo.STR_NORMAL :"正常", - StrInfo.STR_MEASURE_CURRENT :"实测电流", - StrInfo.STR_RATE_CURRENT :"额定电流", - StrInfo.STR_ANGLE :"角度", - StrInfo.STR_AVERAGE_CURRENT :"平均电流", - StrInfo.STR_MAX_CURRENT :"最大电流", - StrInfo.STR_LOW_VOLTAGE_RATE :"欠压值", - StrInfo.STR_MEASURE_VOLTAGE :"实测电压", - StrInfo.STR_ZERO_CURRENT :"零序电流", - StrInfo.STR_ZERO_VOLTAGE :"零序电压", - StrInfo.STR_RECORD :"记录", - StrInfo.STR_LEEAKGE_LOCK_VALUE :"闭锁设定值", - StrInfo.STR_LEEAKGE_ACTIVE_VALUE :"动作设定值", - StrInfo.STR_MEASURE_RESISTOR :"电阻测量值", - StrInfo.STR_FRONT_CIRCUIT :"前机", - StrInfo.STR_NEXT_CIRCUIT :"后机", - StrInfo.STR_RATE_VOLTAGE :"额定电压", - StrInfo.STR_PARA_MODIFY_ERROR :"参数修改失败", - StrInfo.STR_LEEKAGE_RES_FINISH :"闭锁电阻检测完", - StrInfo.STR_LEEKAGE_RES_MEASURE :"闭锁电阻检测中", - StrInfo.STR_SFJ_MONITOR :"双风机磁力监控", - StrInfo.STR_CL_MONITOR :"磁力监控系统", - StrInfo.STR_CL_DB_MONITOR :"双回路磁力监控", - StrInfo.STR_YB_MONITOR :"移变低压侧", - StrInfo.STR_KUI_DIAN_MONITOR :"馈电开关监控", - StrInfo.STR_TYPE :"类型:", - StrInfo.STR_TOP_SWITCH :"总开关", - StrInfo.STR_BOTTOM_SWITCH :"分开关", - StrInfo.STR_COS_V :"COS(ΦaΦbΦc)", - StrInfo.STR_POWER_VI :"有功功率", - StrInfo.STR_POWER_VI_T :"电量", - StrInfo.STR_FRONT_POWER_ON :"前机合", - StrInfo.STR_NEXT_POWER_ON :"后机合", - StrInfo.STR_FRONT_POWER_OFF :"前机分", - StrInfo.STR_NEXT_POWER_OFF :"后机分", - StrInfo.STR_FRONT_RESISTOR :"前机电阻:", - StrInfo.STR_NEXT_RESISTOR :"后机电阻:", - StrInfo.STR_WORK_MODE :"模式:", - StrInfo.STR_LEEKAGE_RES :"漏电电阻", - StrInfo.STR_REVERSE_VOLTAGE :"反电动势\n注意安全", - StrInfo.STR_LIGHT :"照明", - StrInfo.STR_SIGNAL :"信号", - StrInfo.STR_SWITCH_STATUS :"开关状态", - StrInfo.STR_POWER_ON_COUNTS :"合闸次数", - StrInfo.STR_SETTING :"设定值", - StrInfo.STR_POW_U :"无功功率", - StrInfo.STR_TEST_FAIL :"测试不正确", - StrInfo.STR_LEAKAGE_TEST_FAIL :"漏电测试不正确", - StrInfo.STR_DETECT_FAIL_WHEN_POWER_ON :"合闸时不能检测", - StrInfo.STR_LINK :"联机系统", - StrInfo.STR_SINGLE :"单机系统", - StrInfo.STR_STATUS :"状态", - StrInfo.STR_MAIN_FIRST :"主机优先", - StrInfo.STR_MAIN_BAK_SAME :"主辅对等", - StrInfo.STR_MAIN_BAK_SWITCH :"主辅轮动", - StrInfo.STR_SWITCH_DISABLE :"局扇模式", - StrInfo.STR_MAIN :"主机", - StrInfo.STR_BACKUP :"备机", - StrInfo.STR_SINGLE_CIRCUIT_FRONT :"单前机", - StrInfo.STR_SINGLE_CIRCUIT_NEXT :"单后机", - StrInfo.STR_DOUBLE_CIRCUIT :"双回路", - StrInfo.STR_WATER_PUMP_ON :"水泵已开阀", - StrInfo.STR_WATER_PUMP_OFF :"水泵已关阀", - StrInfo.STR_SWITCH_FAIL :"粘连", - StrInfo.STR_SWITCH_THROUGH_2 :"击穿", - StrInfo.STR_GB_MONITOR :"高压真空配电装置", - StrInfo.STR_GB_PROTECT_SYSTEM :"综合保护监控系统", - StrInfo.STR_YBGY_MONITOR :"移变高压侧", - StrInfo.STR_ERROR :"故障", - StrInfo.STR_TEMPERATURE:"温度", - StrInfo.STR_NEXT_CURRENT :"后机电流", - StrInfo.STR_FRONT_CURRENT :"前机电流", - StrInfo.STR_FJ_WS_LOCK :"风机处瓦斯闭锁", - StrInfo.STR_GZM_WS_LOCK :"工作面瓦斯闭锁", - StrInfo.STR_CURRENT :"电流", - StrInfo.STR_VOLTAGE:"电压", - StrInfo.STR_MONITOR_RES :"监视电阻", - StrInfo.STR_SWITCH_THROUGH_SIMPLE :"击穿", - StrInfo.STR_LINK_FAIL :"联机失败", - StrInfo.STR_RES_OFF :"漏电临界值", - StrInfo.STR_ANOTHER_REPAIR :"另台维修请勿停机", - StrInfo.STR_WS_INTENSITY :"瓦斯浓度", - StrInfo.STR_HIGH_VOLT :"高压", - StrInfo.STR_AUTO :"自动", - StrInfo.STR_MANUAL :"手动", - StrInfo.STR_FREQUENCY :"频率", - StrInfo.STR_FWD_ON :"正向启动", - StrInfo.STR_RVS_ON :"反向启动", - StrInfo.STR_TEMPERATURE_UNIT : "℃", - StrInfo.STR_POWER_LOSS :"系统断电", - StrInfo.STR_CALIBRATE_SUCCESS :"标定成功", - StrInfo.STR_ISOLATE_RES :"绝缘电阻", - StrInfo.STR_WATER_MONITOR :"水位控制排水监控系统", - StrInfo.STR_SWTICH_PROTECTOR :"ZDB-200电动机保护器", - StrInfo.STR_INDEPENDENT :"独立模式", - StrInfo.STR_DEPENDENT :"联动模式", - StrInfo.STR_OUT_POSITION : "未到位", - StrInfo.STR_IN_POSITION : "进到位", - StrInfo.STR_QUIT_IN_POSITION : "退到位", - StrInfo.STR_RUN_DATA : "运行数据", - StrInfo.STR_WATER_MODE : "水位", - StrInfo.STR_INV_MODE : "可逆", - StrInfo.STR_ISOLATE_RESISTOR_LOW : "绝缘电阻降低", - StrInfo.STR_SWITCH : "开关", - StrInfo.STR_DIDAO : "地刀", - StrInfo.STR_REMOTE : "程控", - StrInfo.STR_LOCAL : "就地", - StrInfo.STR_ONE_KEY_LOCK : "闭锁中", - StrInfo.STR_COMM_FAIL : "通讯失败", - }}, - - {"alias_company": {0: "浙江志展智能科技", - 1: "华荣科技", - } - }, - {"alias_sensor" : {0: "10 A", 1: "30 A", 2: "50 A", 3: "75 A", 4: "80 A", 5: "100 A", - 6: "120 A", 7: "150 A", 8: "200 A", 9: "300 A", 10: "315 A", 11: "400 A", - 12: "500 A", 13: "600 A", 14: "630 A", 15: "800 A", 16: "1000 A", 17: "1250 A", - 18: "1300 A", 19: "1600 A", 20: "160 A", 21: "250 A", 22: "750 A", 23: "1200 A", - 24: "1500 A", 25: "2000 A", 26: "2500 A" ,27: "5 A"}}, - {"alias_switch_type" : {0: "总开关", 1: "分开关"}}, - {"alias_measure_v": {0: "正电压", 1: "负电压"}}, - {"alias_select": {0: "工频负载", 1:"变频负载"}}, - {"alias_bool": {0:"关闭", 1:"打开"}}, - {"alias_voltage": {0:"380V", 1:"660V", 2:"1140V", 3:"3300V", 4:"100V", 5:"127V", 6:"220V", 7:"440V"}}, - {"alias_parity": {0: "无校验", 1: "奇校验", 2: "偶校验"}}, - {"alias_baud": {0: "1200", 1: "2400", 2: "4800", 3: "9600", 4:"19200", 5:"38400", 6:"51200", 7:"115200"}}, - {"alias_input": {0: "常开", 1: "常闭"}}, - {"alias_onoff": {0: "分闸", 1: "合闸"}}, - {"alias_test": {0: "模拟测试", 1: "继电器测试"}}, - {"alias_can_baud": {0: "1000K", 1: "800K", 2: "500K", 3: "250K", 4: "125K", 5: "100K", 6: "50K", 7: "20K", 8: "10K", 9: "AUTO"}}, - {Alias.alias_measure_v: {0: "正电压", 1: "负电压"}}, - {Alias.alias_switch_type : {0: "总开关", 1: "分开关"}}, - {"alias_work_mode": {0: "水位模式", 1: "磁力模式", 2: "正反转模式", 3: "联控模式"}}, - {"alias_us_phase": {0: "Uab_ABC", 1: "Uab_ACB", 2: "Ubc_ABC", 3: "Ubc_ACB", 4: "Uca_ABC", 5: "Uca_ACB"}}, - {Alias.alias_sensor : {0: "10 A", 1: "30 A", 2: "50 A", 3: "75 A", 4: "80 A", 5: "100 A", - 6: "120 A", 7: "150 A", 8: "200 A", 9: "300 A", 10: "315 A", 11: "400 A", - 12: "500 A", 13: "600 A", 14: "630 A", 15: "800 A", 16: "1000 A", 17: "1250 A", - 18: "1300 A", 19: "1600 A", 20: "160 A", 21: "250 A", 22: "750 A", 23: "1200 A", - 24: "2500 A", 25: "5 A"}}, - {"alias_table": {0: "0", 1: "1", 2: "2", 3: "3"}}, - {"alias_remote": {0: "就地", 1: "程控"}}, - {"alias_current": {0: "测量模式", 1: "平均模式"}}, - - {Alias.alias_eth : {0: "无", 1: "一代以太网", 2: "二代以太网"}}, - {Alias.alias_lcd : {0: "一体迪文屏", 1: "分体迪文屏", 2: "大彩屏", 3 : "昆仑通态屏"}}, - {Alias.alias_fyj : {0: "无", 1: "FYJ", 2: "FYJ2", 3 : "FYJ4"}}, - {Alias.alias_dev : {0: "馈电", 1: "高爆", 2: "移变", 3 : "双风机", 4 : "磁力", - 5 : "双磁力", 6 : "照明", 7 : "移变高压侧", 8: "双高爆", - 9: "组合馈电", 10: "双照明", 11 : "ZZ630"}}, - {"alias_alarm_type": {0: "试验", 1: "动作"}}, - {"alias_car_position": {0: "小车未到位", 1 : "小车试验位", 2: "小车工作位", 3 : "位置信号异常"}}, -] - -MENU_PROPERTY_READ_ONLY = 0 -MENU_PROPERTY_USER = 1 -MENU_PROPERTY_ENGINEER = 2 -MENU_PROPERTY_WRITE_ONLY = 3 - - -def get_alias_value_str(alias_str, alias_value) : - alias_value_msg = None - compare_value = int(alias_value) - - for alias_dict in alias_table : - for alias_name, value_dict in alias_dict.items(): - if isinstance(alias_name, Enum): - alias_name = alias_name.name - - if alias_name == alias_str : - for each_value_dict in value_dict.items(): - if isinstance(each_value_dict[0], Enum) : - key_value = each_value_dict[0].value[0] - else : - key_value = each_value_dict[0] - key_string = each_value_dict[1] - - if int(key_value) == compare_value : - alias_value_msg = key_string - return alias_value_msg - return alias_value_msg - -def func_adjust_current_menu_item(device : class_modbus_comm_device, menu_item) : - #获得互感器类型, 根据互感器类型来调整 scale, format, 让电流可以正确显示与设置 - sensor_type = device.comm_get_value_from_mqtt_name("Sensor") - sensor_current = 400 - - if sensor_type != None : - value_str = get_alias_value_str("alias_sensor", sensor_type) - if value_str != None : - value_str_no_unit = value_str.replace("A", "") - sensor_current = int(value_str_no_unit) - - #80A 以下电流互感器, 显示一位小数点 - if sensor_current <= 80 : - new_item = menu_item - new_item["scale"] = 0.1 - new_item["format"] = "%1.1f" - return new_item - else : - return menu_item - -def func_caculate_Cosf(device : class_modbus_comm_device, menu_item, mqtt_dict : dict = None) : - format_str = utils.dict_or_object_get_attr(menu_item, "format", "%1.0f") - try : - cosa = device.comm_get_value_from_mqtt_name("Cosa") - cosb = device.comm_get_value_from_mqtt_name("Cosb") - cosc = device.comm_get_value_from_mqtt_name("Cosc") - cosf = (cosa + cosb + cosc) / 3 - except Exception as e : - cosf = 0.0 - Cosf_str = format_str%(cosf) - mqtt_dict["Cosf"] = Cosf_str - -#视频触发 -def func_video_trigger(device : class_modbus_comm_device, menu_item, mqtt_dict : dict = None) : - value = device.comm_get_value_from_menu_item(menu_item) - if value == None : - #通讯未建立 - return - - value = round(value) - in_position = (value >> 10) & 0x1 - out_position = (value >> 9) & 0x1 - now_time = time.time() - if hasattr(device, "MqttVideoActive") == False: - #动态添加视频触发所需的变量 - device.MqttVideoActive = False - device.MqttVideoBaseTime = now_time - device.DI_SwitchInPosition = in_position - device.DI_SwitchQuitPosition = out_position - - if in_position != device.DI_SwitchInPosition or out_position != device.DI_SwitchQuitPosition: - #开关进到位与 开关退到位信号, 当这两个状态发生变化时, 触发20秒的视频 - device.MqttVideoActive = True - device.MqttVideoBaseTime = now_time - mqtt_dict["VideoActive"] = "1" - if device.MqttVideoActive : - #视频延时20后主动关闭视频显示 - if now_time - device.MqttVideoBaseTime > 20.0 : - mqtt_dict["VideoActive"] = "0" - device.MqttVideoActive = False - - device.DI_SwitchInPosition = in_position - device.DI_SwitchQuitPosition = out_position - - -COLOR_RED = "#EE2D2D" -COLOR_GREEN = "#83BF6E" - -def func_process_car_message(device : class_modbus_comm_device, menu_item, mqtt_dict : dict = None) : - car_pos_value = device.comm_get_value_from_menu_item(menu_item) - if car_pos_value == None or mqtt_dict == None: - return - car_msg = get_alias_value_str("alias_car_position", car_pos_value) - if car_msg != None : - mqtt_dict["CarPositionMsg"] = car_msg - -def func_process_alarm_message(device : class_modbus_comm_device, menu_item, mqtt_dict : dict = None) : - alarm_id = device.comm_get_value_from_menu_item(menu_item) - if alarm_id == None or mqtt_dict == None: - #通讯未建立 - return - alarm_msg = get_alias_value_str("alias_alarm", alarm_id) - if alarm_msg != None : - alarm_msg_dict = {} - if alarm_id > 0 : - alarm_msg_dict["value"] = alarm_msg - alarm_msg_dict["color"] = COLOR_RED - else : - alarm_msg_dict["value"] = alarm_msg - alarm_msg_dict["color"] = COLOR_GREEN - - mqtt_dict["AlarmMessage"] = alarm_msg_dict - -mqtt_video_trigger = [ - { - "name": "视频触发", - "addr": "8015", - "call" : func_video_trigger, - }, -] - -mqtt_time_update = [ - { - "name": "Year", - "addr": "2300", - "format" : "%04.0f", - "mqtt" : "Year", - }, - { - "name": "Month", - "addr": "2301", - "format" : "%02.0f", - "mqtt" : "Month", - }, - { - "name": "Day", - "addr": "2302", - "format" : "%02.0f", - "mqtt" : "Day", - }, - { - "name": "Hour", - "addr": "2303", - "format" : "%02.0f", - "mqtt" : "Hour", - }, - { - "name": "Minute", - "addr": "2304", - "format" : "%02.0f", - "mqtt" : "Minute", - }, - { - "name": "Second", - "addr": "2305", - "format" : "%02.0f", - "mqtt" : "Second", - }, - { - "name": "SetupTime", - "addr": "2305", - "mqtt" : "SetupTime", - "action" : "SetupTime", - }, -] - -mqtt_pack_param = [ - #系统设置 - { - "name": "开关类型", - "addr": "8210", - "alias" : "alias_switch_type", - "mqtt" : "SwitchType", - }, - { - "name": "瓦斯触点", - "addr": "8190", - "alias" : "alias_input", - "mqtt" : "Gas", - }, - { - "name": "瓦斯延时", - "addr": "8191", - "scale" : 0.01, - "format": "%06.2f", - "mqtt" : "GasDelay", - }, - { - "name": "瓦斯浓度", - "addr": "8237", - "scale" : 0.01, - "format": "%05.2f", - "mqtt" : "GasConcentration", - }, - { - "name": "风电触点", - "addr": "8248", - "alias" : "alias_input", - "mqtt" : "Fan", - }, - { - "name": "风电延时", - "addr": "8234", - "scale" : 0.01, - "format": "%06.2f", - "mqtt" : "FanDelay", - }, - { - "name": "远近控模式", - "addr": "8558", - "alias" : "alias_remote", - "mqtt" : "FarAndNearMode", - }, - { - "name": "维修模式", - "addr": "8565", - "alias" : "alias_bool", - "mqtt" : "MaintenanceMode", - }, - { - "name": "小车报警延时", - "addr": "8576", - "scale" : 0.1, - "format": "%05.1f", - "mqtt" : "CarAlarmDelay", - }, - - { - "name": "断电延时", - "addr": "8249", - "format": "%06.1f", - "scale" : 0.1, - "mqtt" : "OffVoltageDelay", - }, - { - "name": "真空管粘连延时", - "addr": "8209", - "format": "%05.2f", - "scale" : 0.01, - "mqtt" : "TubeDelay", - }, - { - "name": "负载选择", - "alias": "alias_select", - "addr": "8254", - "mqtt" : "LoadSelect", - }, - { - "name": "温度设定", - "addr": "8423", - "scale" : 1, - "format": "%03.0f", - "mqtt" : "Temperature", - }, - { - "name": "触头温度设定", - "addr": "8496", - "scale" : 0.1, - "format": "%05.1f", - "mqtt" : "TemperatureContact", - }, - #电流参数 - { - "name": "额定电流", - "unit": "A", - "addr": "8200", - "scale" : 1.0, - "format": "%04.0f", - "action": "rate_current", - "mqtt" : "RateCurrent", - "adjust" : func_adjust_current_menu_item, - }, - - { - "name": "短路倍数", - "unit": "Ie", - "scale" : 0.01, - "format": "%05.2f", - "addr": "8201", - "min" : 1.0, - "max" : 10.0, - "mqtt" : "ShortLevel", - }, - { - "name": "短路延时", - "unit": "ms", - "scale" : 1.0, - "format": "%03.0f", - "addr": "8198", - "min" : 0.0, - "max" : 200.0, - "mqtt" : "ShortDelay", - }, - { - "name": "互感器类型", - "alias" :"alias_sensor", - "addr": "8207", - "mqtt" : "Sensor", - }, - { - "name": "不平衡值", - "unit": "%", - "addr": "8213", - "scale" : 1.0, - "format": "%03.0f", - "min" : 10.0, - "max" : 100.0, - "mqtt" : "UnbalanceLevel", - }, - { - "name": "不平衡延时", - "unit": "s", - "addr": "8197", - "scale" : 0.1, - "format": "%04.1f", - "mqtt" : "UnbalanceDelay", - }, - { - "name": "定时限过流", - "unit": "Ie", - "addr": "8239", - "scale" : 0.01, - "format": "%04.2f", - "mqtt" : "TimeOvercurrent", - }, - { - "name": "定时限过流延时", - "unit": "ms", - "addr": "8240", - "scale" : 1, - "format": "%05.0f", - "mqtt" : "TimeOvercurrentDelay", - }, - { - "name": "定时限短路", - "unit": "Ie", - "addr": "8523", - "scale" : 0.01, - "format": "%04.2f", - "mqtt" : "TimeLimitcurrent", - }, - { - "name": "定时限短路延时", - "unit": "ms", - "addr": "8524", - "scale" : 1, - "format": "%03.0f", - "mqtt" : "TimeLimitcurrentDelay", - }, - { - "name": "Ia 校正", - "unit": "%", - "scale" : 0.1, - "format": "%05.1f", - "addr": "8217", - "min" : 60.0, - "max" : 130.0, - "mqtt" : "CorrectIa", - }, - { - "name": "Ib 校正", - "unit": "%", - "scale" : 0.1, - "format": "%05.1f", - "addr": "8218", - "min" : 60.0, - "max" : 130.0, - "mqtt" : "CorrectIb", - }, - { - "name": "Ic 校正", - "unit": "%", - "scale" : 0.1, - "format": "%05.1f", - "addr": "8219", - "min" : 60.0, - "max" : 130.0, - "mqtt" : "CorrectIc", - }, - - - #电压参数 - { - "name": "额定电压", - "addr": "8211", - "alias": "alias_voltage", - "mqtt" : "RateVoltage", - }, - { - "name": "欠压比值", - "unit": "%", - "addr": "8202", - "scale" : 0.1, - "format": "%05.1f", - "min" : 60.0, - "max" : 100.0, - "mqtt" : "PercentLowVoltage", - }, - { - "name": "欠压延时", - "unit": "s", - "addr": "8177", - "scale" : 0.01, - "format": "%05.2f", - "min" : 0.1, - "max" : 60.0, - "mqtt" : "DelayLowVoltage", - }, - { - "name": "过压比值", - "unit": "%", - "addr": "8224", - "scale" : 0.1, - "format": "%05.1f", - "min" : 100.0, - "max" : 150.0, - "mqtt" : "PercentHighVoltage", - }, - { - "name": "过压延时", - "unit": "s", - "addr": "8176", - "scale" : 0.01, - "format": "%05.2f", - "min" : 0.1, - "max" : 60.0, - "mqtt" : "DelayHighVoltage", - }, - { - "name": "Ua校正", - "unit": "%", - "addr": "8220", - "scale" : 0.1, - "format": "%05.1f", - "min" : 60.0, - "max" : 130.0, - "mqtt" : "CorrectUa", - }, - { - "name": "Ub校正", - "unit": "%", - "addr": "8221", - "scale" : 0.1, - "format": "%05.1f", - "min" : 60.0, - "max" : 130.0, - "mqtt" : "CorrectUb", - }, - { - "name": "Uc校正", - "unit": "%", - "addr": "8222", - "scale" : 0.1, - "format": "%05.1f", - "min" : 60.0, - "max" : 130.0, - "mqtt" : "CorrectUc", - }, - { - "name": "Us校正", - "unit": "%", - "addr": "8214", - "scale" : 0.1, - "format": "%05.1f", - "min" : 60.0, - "max" : 130.0, - "mqtt" : "CorrectUs", - }, - - - #漏电参数 - { - "name": "零序电流", - "addr": "2007", - "unit": "mA", - "scale" : 0.1, - "format" : "%05.1f", - "mqtt" : "KD.Io", - "action" : "Visible_KD", #馈电模式所需菜单 - }, - { - "name": "零序电压", - "addr": "2008", - "unit": "V", - "scale" : 1.0, - "format" : "%04.0f", - "mqtt" : "KD.Uo", - "action" : "Visible_KD", #馈电模式菜单有效 - }, - { - "name": "漏电延时", - "addr": "8205", - "unit": "ms", - "scale" : 1.0, - "format" : "%03.0f", - "mqtt" : "LeakageDelay", - "action" : "Visible_KD_GB", #馈电, 高爆模式所需菜单 - }, - { - "name": "串联电阻", - "addr": "8236", - "unit": "K", - "scale" : 0.1, - "format" : "%05.1f", - "mqtt" : "SeriesResistor" - }, - { - "name": "闭锁电阻", - "addr": "8204", - "unit": "K", - "scale" : 0.1, - "format" : "%05.1f", - "action" : "Hide_GB", #高爆模式下隐藏菜单 - "mqtt" : "BlockResistor" - }, - { - "name": "Uo校正值", - "addr": "8187", - "unit": "%", - "scale" : 0.1, - "format" : "%05.1f", - "action" : "Visible_KD_GB", #馈电与高爆模式菜单有效 - "mqtt" : "CorrectUo" - }, - { - "name": "Io校正值", - "addr": "8196", - "unit": "%", - "scale" : 0.1, - "format" : "%05.1f", - "action" : "Visible_KD_GB", #馈电与高爆模式菜单有效 - "mqtt" : "CorrectIo" - }, - { - "name": "检测电压", - "addr": "8253", - "alias": "alias_measure_v", - "mqtt" : "MeasureV" - }, - { - "name": "漏电投入延时", - "addr": "8252", - "unit": "S", - "scale" : 0.1, - "format" : "%04.1f", - "action" : "Hide_GB", #高爆模式下隐藏菜单 - "default": 3.0, - "mqtt" : "DelayLeakageTrip" - }, - - #保护参数投入 - { - "name": "短路保护", - "alias": "alias_bool", - "addr": "8192.1", - "mqtt" : "ProtectShort", - }, - { - "name": "相敏保护", - "alias": "alias_bool", - "addr": "8192.13", - "mqtt" : "ProtectPhaseSensitivity", - }, - { - "name": "过载保护", - "alias": "alias_bool", - "addr": "8192.3", - "mqtt" : "ProtectOverLoad", - }, - { - "name": "电流断相保护", - "alias": "alias_bool", - "addr": "8192.4", - "mqtt" : "ProtectCurrentPhaseOff", - }, - { - "name": "不平衡保护", - "alias": "alias_bool", - "addr": "8192.2", - "mqtt" : "ProtectImbalance", - }, - { - "name": "漏电闭锁保护", - "alias": "alias_bool", - "addr": "8192.10", - "mqtt" : "ProtectLeakage" - }, - { - "name": "定时限过载保护", - "alias": "alias_bool", - "addr": "8192.11", - "mqtt" : "ProtectTimeLimitOverload" - }, - { - "name": "定时限短路保护", - "alias": "alias_bool", - "addr": "8192.12", - "mqtt" : "ProtectTimeLimitShortCircuit", - }, - { - "name": "欠压保护", - "alias": "alias_bool", - "addr": "8174.1", - "mqtt" : "ProtectUnderVoltage", - }, - { - "name": "过压保护", - "alias": "alias_bool", - "addr": "8174.0", - "mqtt" : "ProtectOverVoltage", - }, - { - "name": "电压断相保护", - "alias": "alias_bool", - "addr": "8174.2", - "mqtt" : "ProtectVoltagePhaseOff", - }, - { - "name": "漏电动作保护", - "alias": "alias_bool", - "addr": "8174.6", - "mqtt" : "ProtectLeakageAction", - }, - { - "name": "真空管粘连保护", - "alias": "alias_bool", - "addr": "8174.15", - "mqtt" : "ProtectTubeAdhesion", - }, - { - "name": "温度报警保护", - "alias": "alias_bool", - "addr": "8174.8", - "mqtt" : "ProtectTemperatureAlarm", - }, - - #通讯设置 - { - "name": "485地址", - "addr": "8212", - "format": "%03.0f", - "mqtt" : "485Address", - }, - { - "name": "485波特率", - "alias": "alias_baud", - "addr": "8188", - "mqtt" : "485Baud", - }, - { - "name": "485校验", - "alias": "alias_parity", - "addr": "8194", - "mqtt" : "485Parity", - }, - { - "name": "CAN地址", - "format": "%03.0f", - "addr": "8440", - "mqtt" : "CANAddress", - }, - { - "name": "CAN波特率", - "alias": "alias_can_baud", - "addr": "8439", - "mqtt" : "CANBaud", - }, -] - -mqtt_pack_measure = [ - { - "name": "SwitchStatus", - "addr": "8162.0", - "alias": Alias.alias_onoff, - "remap_addr": remap.COMM_REMAP_MEASURE_SWITCH_STATUS, - "measure" : True, - "mqtt" : "SwitchStatus", - }, - { - "name": "AlarmId", - "addr": "8166", - "alias": Alias.alias_alarm, - "remap_addr": remap.COMM_REMAP_MEASURE_SWITCH_ALARM, - "measure" : True, - "mqtt" : "AlarmId", - }, - { - "name": "AlarmMessage", - "addr": "8166", - "alias": Alias.alias_alarm, - "call" : func_process_alarm_message, - }, - { - "name": "CarPositionMsg", - "addr": "8015.10#2", - "alias": Alias.alias_car_position, - "call" : func_process_car_message, - }, - { - "name": "Ia", - "unit": "A", - "addr": "8156", - "format": "%05.1f", - "remap_addr": remap.COMM_REMAP_MEASURE_FLOAT_IA, - "measure" : True, - "mqtt" : "Ia", - "adjust" : func_adjust_current_menu_item, - }, - { - "name": "Ib", - "unit": "A", - "addr": "8157", - "format": "%05.1f", - "remap_addr": remap.COMM_REMAP_MEASURE_FLOAT_IB, - "measure" : True, - "mqtt" : "Ib", - "adjust" : func_adjust_current_menu_item, - }, - { - "name": "Ic", - "unit": "A", - "addr": "8158", - "format": "%05.1f", - "remap_addr": remap.COMM_REMAP_MEASURE_FLOAT_IC, - "measure" : True, - "mqtt" : "Ic", - "adjust" : func_adjust_current_menu_item, - }, - { - "name": "Voltage", - "unit": "V", - "addr": "8153", - "format": "%05.0f", - "remap_addr": remap.COMM_REMAP_MEASURE_FLOAT_UAB, - "measure" : True, - "mqtt" : "Voltage", - }, - { - "name": "Current", - "unit": "A", - "addr": "8156", - "format": "%05.1f", - "remap_addr": remap.COMM_REMAP_MEASURE_FLOAT_IA, - "measure" : True, - "mqtt" : "Current", - }, - { - "name": "Power", - "unit": "kw", - "addr": "8167", - "format": "%07.0f", - "measure" : True, - "mqtt" : "Power", - }, - { - "name": "Electricity", - "unit": "kwh", - "addr": "8160#2", - "format": "%07.0f", - "measure" : True, - "mqtt" : "Electricity", - }, - { - "name": "Uab", - "unit": "V", - "addr": "8153", - "format": "%05.0f", - "remap_addr": remap.COMM_REMAP_MEASURE_FLOAT_UAB, - "measure" : True, - "mqtt" : "Uab", - }, - { - "name": "Ubc", - "unit": "V", - "addr": "8154", - "format": "%05.0f", - "remap_addr": remap.COMM_REMAP_MEASURE_FLOAT_UBC, - "measure" : True, - "mqtt" : "Ubc", - }, - { - "name": "Uca", - "unit": "V", - "addr": "8155", - "format": "%05.0f", - "remap_addr": remap.COMM_REMAP_MEASURE_FLOAT_UCA, - "measure" : True, - "mqtt" : "Uca", - }, - { - "name": "Uo", - "unit": "V", - "addr": "8152", - "format": "%05.1f", - "remap_addr": remap.COMM_REMAP_MEASURE_FLOAT_UO, - "measure" : True, - "mqtt" : "Uo", - }, - { - "name": "Io", - "unit": "mA", - "addr": "8151", - "format": "%05.1f", - "scale" : 1.0, - "remap_addr" : remap.COMM_REMAP_MEASURE_FLOAT_IO, - "measure" : True, - "mqtt" : "Io", - }, - { - "name": "R", - "unit": "K", - "addr": "8150", - "scale": 0.1, - "format": "%05.1f", - "remap_addr": remap.COMM_REMAP_MEASURE_FLOAT_RO, - "measure" : True, - "mqtt" : "R", - }, - { - "name": "合闸次数", - "addr": "8169", - "format": "%06.0f", - "property": MENU_PROPERTY_READ_ONLY, - "mqtt" : "OnCount", - }, - { - "name": "Cosa", - "addr": "8172#s", - "scale": 0.01, - "format": "%04.2f", - "measure" : True, - "mqtt" : "Cosa", - }, - { - "name": "Cosb", - "addr": "8171#s", - "scale": 0.01, - "format": "%04.2f", - "measure" : True, - "mqtt" : "Cosb", - }, - { - "name": "Cosc", - "addr": "8170#s", - "scale": 0.01, - "format": "%04.2f", - "measure" : True, - "mqtt" : "Cosc", - }, - { - "name": "Cosf", - "addr": "8171#s", - "scale": 0.01, - "format": "%04.2f", - "measure" : True, - "call" : func_caculate_Cosf, - }, - { - "name": "AngleUoIo", - "addr": "8149", - "format": "%04.2f", - "measure" : True, - "mqtt" : "AngleUoIo", - }, - { - "name": "A相上", - "addr": "8056#s", - "format": "%05.1f", - "measure" : True, - "mqtt" : "Aup", - }, - - { - "name": "B相上", - "addr": "8057#s", - "format": "%05.1f", - "measure" : True, - "mqtt" : "Bup", - }, - { - "name": "C相上", - "addr": "8058#s", - "format": "%05.1f", - "measure" : True, - "mqtt" : "Cup", - }, - { - "name": "A相下", - "addr": "8059#s", - "format": "%05.1f", - "measure" : True, - "mqtt" : "Adown", - }, - { - "name": "B相下", - "addr": "8060#s", - "format": "%05.1f", - "measure" : True, - "mqtt" : "Bdown", - }, - { - "name": "C相下", - "addr": "8061#s", - "format": "%05.1f", - "measure" : True, - "mqtt" : "Cdown", - }, -] - -mqtt_pack_alarm = [ - { - "name": "AlarmCode", - "addr": "8121", - "alias": "alias_alarm", - "mqtt" : "AlarmCode", - }, - { - "name": "AlarmTest", - "addr": "8138", - "alias": "alias_alarm_type", - "format" : "%1.0f", - "mqtt" : "AlarmTest", - }, - { - "name": "Ua", - "addr": "8122", - "format" : "%1.0f", - "mqtt" : "AlarmUa", - }, - { - "name": "Ub", - "addr": "8123", - "format" : "%1.0f", - "mqtt" : "AlarmUb", - }, - { - "name": "Uc", - "addr": "8124", - "format" : "%1.0f", - "mqtt" : "AlarmUc", - }, - { - "name": "Ia", - "addr": "8125", - "format" : "%1.0f", - "mqtt": "AlarmIa", - "adjust" : func_adjust_current_menu_item, - }, - { - "name": "Ib", - "addr": "8126", - "format" : "%1.0f", - "mqtt": "AlarmIb", - "adjust" : func_adjust_current_menu_item, - }, - { - "name": "Ic", - "addr": "8127", - "format" : "%1.0f", - "mqtt": "AlarmIc", - "adjust" : func_adjust_current_menu_item, - }, - { - "name": "Ro", - "addr": "8128", - "format" : "%5.1f", - "scale" : 0.1, - "mqtt": "AlarmRo", - }, - { - "name": "Io", - "addr": "8129", - "format" : "%1.1f", - "scale" : 0.1, - "mqtt": "AlarmIo", - }, - { - "name": "Uo", - "addr": "8130", - "format" : "%5.0f", - "scale" : 1.0, - "mqtt": "AlarmUo", - }, - { - "name": "Year", - "addr": "8131", - "format" : "%4.0f", - "mqtt": "AlarmYear", - }, - { - "name": "Month", - "addr": "8132", - "format" : "%2.0f", - "mqtt": "AlarmMonth", - }, - { - "name": "Day", - "addr": "8133", - "format" : "%2.0f", - "mqtt": "AlarmDay", - }, - { - "name": "Hour", - "addr": "8134", - "format" : "%2.0f", - "mqtt": "AlarmHour", - }, - { - "name": "Minute", - "addr": "8135", - "format" : "%2.0f", - "mqtt": "AlarmMinute", - }, - { - "name": "Second", - "addr": "8136", - "format" : "%2.0f", - "mqtt": "AlarmSecond", - }, -] - -menu_data = [ - { - "name": "数据页面", - "sub_menu": "menu_curve_physical", - }, -] - -#曲线菜单 -menu_curve_physical = [ - { - "name": "物理曲线", - "property" : MENU_PROPERTY_READ_ONLY, - "action" : "Idle", - }, -] - -#曲线菜单 -menu_curve_adc = [ - { - "name": "ADC曲线", - "property" : MENU_PROPERTY_READ_ONLY, - "action" : "Idle", - }, -] - -#谐波菜单 -menu_curve_harmonic = [ - { - "name": "谐波曲线", - "property" : MENU_PROPERTY_READ_ONLY, - "action" : "Idle", - }, -] - -# modbus_comm_table = [ -# {"name":"alarm", "reg_addr":8120, "reg_count":25, "cycle": 0, "mqtt_pack": mqtt_pack_alarm}, -# {"name":"measure", "reg_addr":8000, "reg_count":62, "cycle": 500, "mqtt_pack": mqtt_video_trigger}, -# {"name":"measure", "reg_addr":8139, "reg_count":35, "cycle": 200, "mqtt_pack": mqtt_pack_measure}, -# {"name":"comm_cmd", "reg_addr":100618, "reg_count":32, "cycle": 100}, -# #{"name":"key_group", "reg_addr":1000, "reg_count":18, "cycle": 20}, -# # {"name":"para_group", "reg_addr":2000, "reg_count":32, "cycle": 0}, -# {"name":"time_group", "reg_addr":2300, "reg_count":6, "cycle": 1000}, -# {"name":"param/info", "reg_addr":8174, "reg_count":96, "cycle": 3000, "mqtt_pack" : mqtt_pack_param}, -# {"name":"param/info", "reg_addr":8180, "reg_count":60, "cycle": 3000}, -# {"name":"param/info", "reg_addr":8550, "reg_count":30, "cycle": 3000}, -# {"name":"param/info", "reg_addr":8435, "reg_count":10, "cycle": 3000}, -# {"name":"param/info", "reg_addr":2000, "reg_count":32, "cycle": 3000}, -# #{"name":"global_status", "reg_addr":3200, "reg_count":6, "cycle": 400}, -# ] -modbus_comm_table = [ - {"name":"alarm", "reg_addr":8120, "reg_count":25, "cycle": 0, "mqtt_pack": mqtt_pack_alarm}, - {"name":"measure", "reg_addr":8000, "reg_count":62, "cycle": 500, "mqtt_pack": mqtt_video_trigger}, - {"name":"measure", "reg_addr":8139, "reg_count":35, "cycle": 200, "mqtt_pack": mqtt_pack_measure}, - {"name":"comm_cmd", "reg_addr":100618, "reg_count":32, "cycle": 100}, - #{"name":"key_group", "reg_addr":1000, "reg_count":18, "cycle": 20}, - # {"name":"para_group", "reg_addr":2000, "reg_count":32, "cycle": 0}, - {"name":"time_group", "reg_addr":2300, "reg_count":6, "cycle": 1000}, - {"name":"param/info", "reg_addr":8174, "reg_count":96, "cycle": 3000, "mqtt_pack" : mqtt_pack_param}, - {"name":"param/info", "reg_addr":8180, "reg_count":60, "cycle": 3000}, - {"name":"param/info", "reg_addr":8490, "reg_count":10, "cycle": 3000}, - {"name":"param/info", "reg_addr":8520, "reg_count":20, "cycle": 3000}, - {"name":"param/info", "reg_addr":8550, "reg_count":30, "cycle": 3000}, - {"name":"param/info", "reg_addr":8435, "reg_count":10, "cycle": 3000}, - {"name":"param/info", "reg_addr":8420, "reg_count":10, "cycle": 3000}, - {"name":"param/info", "reg_addr":2000, "reg_count":32, "cycle": 3000}, - #{"name":"global_status", "reg_addr":3200, "reg_count":6, "cycle": 400}, -] - -def func_comm_table_trigger_check(object_comm_table, comm_table_item) : - if not hasattr(comm_table_item, "name"): - return False - return False - -menu_current = [ #菜单表[menu_current],存储菜单项属性字典<> - { - "name": "额定电流", - "unit": "A", - "addr": "8200", - "action": "rate_current", - "adjust" : func_adjust_current_menu_item, - }, - { - "name": "短路倍数", - "unit": "Ie", - "scale" : 0.01, - "format": "%05.2f", - "addr": "8201", - "min" : 1.0, - "max" : 10.0, - }, - { - "name": "短路延时", - "unit": "ms", - "scale" : 1.0, - "format": "%03.0f", - "addr": "8198", - "min" : 0.0, - "max" : 200.0, - #"mqtt" : "ShortDelay", - }, - { - "name": "互感器类型", - "alias" : Alias.alias_sensor, - "addr": "8207", - }, - # { - # "name": "反时限表", - # "alias" :"alias_table", - # "addr": "8178", - # }, - { - "name": "不平衡值", - "unit": "%", - "addr": "8213", - "scale" : 1.0, - "format": "%03.0f", - "min" : 10.0, - "max" : 100.0, - #"mqtt" : "UnbalanceLevel", - }, - { - "name": "不平衡延时", - "unit": "s", - "addr": "8197", - "scale" : 0.1, - "format": "%04.1f", - #"mqtt" : "UnbalanceDelay", - }, - { - "name": "B相电流", - "alias": "alias_current", - "addr": "8244", - }, - { - "name": "Ia 校正", - "unit": "%", - "scale" : 0.1, - "format": "%05.1f", - "addr": "8217", - "min" : 60.0, - "max" : 130.0, - #"mqtt" : "CorrectIa", - }, - { - "name": "Ib 校正", - "unit": "%", - "scale" : 0.1, - "format": "%05.1f", - "addr": "8218", - "min" : 60.0, - "max" : 130.0, - #"mqtt" : "CorrectIb", - }, - { - "name": "Ic 校正", - "unit": "%", - "scale" : 0.1, - "format": "%05.1f", - "addr": "8219", - "min" : 60.0, - "max" : 130.0, - #"mqtt" : "CorrectIc", - }, - { - "name": "退出", - "action": "exit", - }, -] - -menu_voltage = [ - { - "name": "额定电压", - "addr": "8211", - "alias": "alias_voltage", - "default": 0, - }, - { - "name": "欠压比值", - "unit": "%", - "addr": "8202", - "scale" : 0.1, - "format": "%05.1f", - "min" : 60.0, - "max" : 100.0, - #"mqtt" : "PercentLowVoltage", - }, - { - "name": "欠压延时", - "unit": "s", - "addr": "8177", - "scale" : 0.01, - "format": "%05.2f", - "min" : 0.1, - "max" : 60.0, - #"mqtt" : "DelayLowVoltage", - }, - { - "name": "过压比值", - "unit": "%", - "addr": "8224", - "scale" : 0.1, - "format": "%05.1f", - "min" : 100.0, - "max" : 150.0, - #"mqtt" : "PercentHighVoltage", - }, - { - "name": "过压延时", - "unit": "s", - "addr": "8176", - "scale" : 0.01, - "format": "%05.2f", - "min" : 0.1, - "max" : 60.0, - #"mqtt" : "DelayHighVoltage", - }, - { - "name": "Ua校正", - "unit": "%", - "addr": "8220", - "scale" : 0.1, - "format": "%05.1f", - "min" : 60.0, - "max" : 130.0, - #"mqtt" : "CorrectUa", - }, - { - "name": "Ub校正", - "unit": "%", - "addr": "8221", - "scale" : 0.1, - "format": "%05.1f", - "min" : 60.0, - "max" : 130.0, - #"mqtt" : "CorrectUb", - }, - { - "name": "Uc校正", - "unit": "%", - "addr": "8222", - "scale" : 0.1, - "format": "%05.1f", - "min" : 60.0, - "max" : 130.0, - #"mqtt" : "CorrectUc", - }, - { - "name": "Us校正", - "unit": "%", - "addr": "8214", - "scale" : 0.1, - "format": "%05.1f", - "min" : 60.0, - "max" : 130.0, - #"mqtt" : "CorrectUs", - }, - { - "name": "退出", - "action": "exit", - }, -] - -menu_alarm_display = [ - { - "name": "当前故障", - "action" : "Idle", - }, -] - -menu_alarm_curve = [ - { - "name": "录波曲线", - "action" : "Idle", - }, -] - -menu_alarm_history = [ - { - "name": "故障查询", - "action" : "Idle", - }, -] - -menu_alarm = [ - { - "name": "故障查询", - "sub_menu": "menu_alarm_history", - }, - { - "name": "故障清除", - "action": "alarm_clear", - }, - { - "name": "合闸清零", - "action": "clear_oncount", - }, - { - "name": "合闸次数", - "addr": "8169", - "format": "%05.0f", - "property": MENU_PROPERTY_READ_ONLY, - #"mqtt" : "OnCount", - }, - { - "name": "电量清除", - "action": "clear_kwh", - }, - { - "name": "累计时间清除", - "action": "clear_time", - }, - { - "name": "累计合闸时间", - "addr": "8016#2", - "unit": "Min", - "scale": 0.0166666666666667, - "format": "%07.0f", - "property": MENU_PROPERTY_READ_ONLY, - }, - { - "name": "退出", - "action": "exit", - }, -] - -menu_test = [ - { - "name": "短路试验", - "action": "test", - "addr" : "100628", - "mqtt" : "TestShort", - }, - { - "name": "漏电试验", - "action": "test", - "addr" : "100629", - "mqtt" : "TestIsolation", - }, - { - "name": "过压试验", - "action": "test", - "addr" : "100641", - "mqtt" : "TestOverVoltage", - }, - { - "name": "电流断相试验", - "action": "test", - "addr" : "100642", - "mqtt" : "TestBreak", - }, - - { - "name": "复归", - "action": "test", - "addr" : "100649", - "mqtt" : "TestRecover", - }, - - { - "name": "漏电试验配置", - "alias" : "alias_test", - "addr": "8265", - }, - { - "name": "退出", - "action": "exit", - }, -] - -menu_protect_set = [ - { - "name": "短路保护", - "alias": Alias.alias_bool, - "addr": "8192.1", - #"mqtt" : "ProtectShort", - }, - { - "name": "不平衡保护", - "alias": "alias_bool", - "addr": "8192.2", - #"mqtt" : "ProtectUnbalance", - }, - { - "name": "反时限过流", - "alias": "alias_bool", - "addr": "8192.3", - #"mqtt" : "ProtectOverCurrent", - }, - { - "name": "过压保护", - "alias": "alias_bool", - "addr": "8174.0", - #"mqtt" : "ProtectHighVotage", - }, - { - "name": "欠压保护", - "alias": "alias_bool", - "addr": "8174.1", - #"mqtt" : "ProtectLowVotage", - }, - # { - # "name": "电压断相", - # "alias": "alias_bool", - # "addr": "8174.2", - # }, - # { - # "name": "相序保护", - # "alias": "alias_bool", - # "addr": "8174.3", - # }, - { - "name": "漏电闭锁", - "alias": "alias_bool", - "addr": "8192.10", - #"mqtt" : "ProtectIsolationLock", - }, - { - "name": "漏电动作", - "alias": "alias_bool", - "addr": "8174.6", - #"mqtt" : "ProtectIsolationAction", - }, - # { - # "name": "选漏保护", - # "alias": "alias_bool", - # "addr": "8174.7", - # }, - { - "name": "风电闭锁", - "alias": "alias_bool", - "addr": "8175.0", - #"mqtt" : "ProtectWindMotor", - }, - { - "name": "瓦斯闭锁", - "alias": "alias_bool", - "addr": "8174.13", - #"mqtt" : "ProtectGasLock", - }, - { - "name": "退出", - "action": "exit", - }, -] - -menu_comm_set = [ - { - "name": "485地址", - "addr": "8212", - "format": "%03.0f", - }, - { - "name": "485波特率", - "alias": "alias_baud", - "addr": "8188", - }, - { - "name": "485校验", - "alias": "alias_parity", - "addr": "8194", - }, - # { - # "name": "CAN地址", - # }, - # { - # "name": "CAN波特率", - # "alias": "alias_can_baud", - # }, - { - "name": "IP设置", - "addr": "8271#2", - "action": "ip", - }, - { - "name": "IP网关", - "addr": "8273#2", - "action": "ip", - }, - { - "name": "IP掩码", - "addr": "8275#2", - "action": "ip", - }, - { - "name": "退出", - "action": "exit", - }, -] - -menu_system = [ - { - "name": "工作模式", - "addr": "8231", - "alias": "alias_work_mode", - "property": MENU_PROPERTY_ENGINEER, - "action" : "Visible_CL", #磁力模式显示菜单 - }, - { - "name": "开关类型", - "alias": "alias_switch_type", - "addr": "8210", - "action" : "Visible_KD", #馈电模式显示菜单 - }, - { - "name": "控制模式", - "alias": "alias_remote", - "addr": "8262", - }, - { - "name": "瓦斯触点", - "alias": "alias_input", - "addr": "8190", - }, - { - "name": "瓦斯延时", - "unit": "S", - "addr": "8191", - "scale": 0.01, - "format": "%05.2f", - }, - { - "name": "风电触点", - "alias": "alias_input", - "addr": "8248", - }, - { - "name": "风电延时", - "unit": "S", - "addr": "8234", - "scale": 0.01, - "format": "%05.2f", - }, - { - "name": "高水位延时", - "addr": "8267", - "unit": "S", - "scale": 0.1, - "format": "%04.1f", - "action" : "Visible_CL_WATER", #水位磁力模式显示 - }, - { - "name": "正反转延时", - "addr": "8266", - "unit": "ms", - "scale": 1.0, - "format": "%04.0f", - "action" : "Visible_CL_INV", #正反转磁力模式显示 - }, - { - "name": "维修模式", - "addr": "8260", - "alias": "alias_bool", - }, - # { - # "name": "温度设定", - # "unit": "℃", - # "addr": "2030", - # "format": "%+03.0f", - # }, - { - "name": "系统日期", - "addr": "2300#3", - "action": "date", - }, - { - "name": "当前时间", - "addr": "2303#3", - "action": "time", - }, - { - "name": "软件版本", - "addr": "8180", - "unit" : VERSION_DATE, - "scale": 0.01, - "format": "%.2f", - "property": MENU_PROPERTY_READ_ONLY, - }, - { - "name": "系统密码", - "addr": "8181", - "format": "%04.0f", - "action": "password", - }, - { - "name": "Us相位", - "alias": "alias_us_phase", - "addr": "8269", - }, - { - "name": "重启", - "action": "restart", - }, - { - "name": "退出", - "action": "exit", - }, -] - -menu_switch_cmd = [ - { - "name": "通讯合闸", - "action": "write_bit", - "addr" : "100618", - "mqtt" : "SwitchOn", - }, - { - "name": "通讯分闸", - "action": "write_bit", - "addr" : "100619", - "mqtt" : "SwitchOff", - }, - { - "name": "通讯复位", - "action": "write_bit", - "addr" : "100620", - "mqtt" : "SwitchRst", - }, - { - "name": "小车进控制", - "addr" : "100636", - "mqtt" : "CarForward", - }, - { - "name": "小车退控制", - "addr" : "100637", - "mqtt" : "CarRetreat", - }, - -] - -memu_setting = [ - { - "name": "电流设置", - "sub_menu": Menu.menu_current, - }, - { - "name": "电压设置", - "sub_menu": "menu_voltage" - }, - { - "name": "漏电设置", - "sub_menu": "menu_leak" - }, - { - "name": "系统设置", - "sub_menu": "menu_system" - }, - { - "name": "保护设置", - "sub_menu": "menu_protect_set" - }, - { - "name": "通讯设置", - "sub_menu": "menu_comm_set" - }, - { - "name": "保护试验", - "sub_menu": Menu.menu_test #"menu_test" - }, - { - "name": "故障查询", - "sub_menu": "menu_alarm" - }, - { - "name": "退出", - "action": "exit", - }, -] - -menu_leak = [ - { - "name": "漏电延时", - "addr": "8205", - "unit": "ms", - "scale" : 1.0, - "format" : "%03.0f", - "action" : "Visible_KD_GB", #馈电, 高爆模式所需菜单 - }, - { - "name": "零序电流", - "addr": "2007", - "unit": "mA", - "scale" : 0.1, - "format" : "%05.1f", - #"mqtt" : "KD.Io", - "action" : "Visible_KD", #馈电模式所需菜单 - }, - { - "name": "零序电压", - "addr": "2008", - "unit": "V", - "scale" : 1.0, - "format" : "%04.0f", - #"mqtt" : "KD.Uo", - "action" : "Visible_KD", #馈电模式菜单有效 - }, - { - "name": "零序电流", - "addr": "2007", - "unit": "A", - "scale" : 0.01, - "format" : "%05.2f", - "mqtt" : "GB.Io", - "action" : "Visible_GB", #高爆模式菜单有效 - }, - { - "name": "零序电压", - "addr": "2008", - "unit": "V", - "scale" : 1.0, - "format" : "%05.2f", - "mqtt" : "GB.Uo", - "action" : "Visible_GB", #高爆模式菜单有效 - }, - { - "name": "Uo校正值", - "addr": "8187", - "unit": "%", - "scale" : 0.1, - "format" : "%05.1f", - "action" : "Visible_KD_GB", #馈电与高爆模式菜单有效 - }, - { - "name": "Io校正值", - "addr": "8196", - "unit": "%", - "scale" : 0.1, - "format" : "%05.1f", - "action" : "Visible_KD_GB", #馈电与高爆模式菜单有效 - }, - { - "name": "闭锁电阻", - "addr": "8204", - "unit": "K", - "scale" : 0.1, - "format" : "%05.1f", - "action" : "Hide_GB", #高爆模式下隐藏菜单 - }, - { - "name": "串联电阻", - "addr": "8236", - "unit": "K", - "scale" : 0.1, - "format" : "%05.1f", - }, - { - "name": "漏电投入延时", - "addr": "8252", - "unit": "S", - "scale" : 0.1, - "format" : "%04.1f", - "action" : "Hide_GB", #高爆模式下隐藏菜单 - "default": 3.0 - }, - { - "name": "检测电压", - "addr": "8253", - "alias": Alias.alias_measure_v, - }, - { - "name": "退出", - "action": "exit", - }, -] - -calibrate = [ - { - "name": "999校正", - "action": "calibrate999", - "mqtt" : "Calibrate999", - }, - { - "name": "0欧校正", - "action": "calibrate0", - "mqtt" : "Calibrate0", - }, - { - "name": "以太网模块", - "alias": Alias.alias_eth, - "addr" : "8280", - }, - { - "name": "LCD模块", - "alias": Alias.alias_lcd, - "addr" : "8281", - }, - { - "name": "防越级模块", - "alias": Alias.alias_fyj, - "addr" : "8282", - }, - { - "name": "设备型号", - "alias": Alias.alias_dev, - "addr" : "8270", - }, - { - "name": "退出", - "action": "exit", - }, -] - -startup = [ - { - "name": "退出", - }, -] - -menu_main = [ - { - "name": "设置", - "sub_menu": "memu_setting", - }, - { - "name": "数据", - "sub_menu": "menu_data", - }, - { - "name": "报警", - "sub_menu": "menu_alarm_display", - }, - { - "name": "标定", - "sub_menu": "calibrate", - "property": MENU_PROPERTY_ENGINEER, - }, -] - -mqtt_topic_subscribe = None - -MENU_STARTUP_PAGE = 150 -MENU_DISPLAY_PAGE = 2 -MENU_ALARM_PAGE = 3 -MENU_DATA_PAGE = 120 -MENU_CL_MAIN_PAGE = 90 -MENU_KD_MAIN_PAGE = 20 -MENU_KD_MAIN_PAGE_LANGUAGE = 21 -MENU_CURVE_PAGE = 10 -MENU_ADC_CURVE_PAGE = 18 -MENU_HARNOMIC_CURVE_PAGE = 19 - -menu_caption = [ - {"name" : "startup", "menu" : startup, "caption": "启动页面", "page" : MENU_STARTUP_PAGE, "max_items" : 1}, - {"name" : "menu_main", "menu" : menu_main, "caption": "主菜单", "page" : MENU_KD_MAIN_PAGE, "max_items" : 4}, - {"name" : "menu_leak", "menu" : menu_leak, "caption": "漏电设置", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "memu_setting", "menu" : memu_setting, "caption": "参数设置", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "menu_current", "menu" : menu_current, "caption": "电流设置", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "menu_voltage", "menu" : menu_voltage, "caption": "电压设置", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "menu_system", "menu" : menu_system, "caption": "系统设置", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "menu_protect_set", "menu" : menu_protect_set, "caption": "保护设置", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "menu_comm_set", "menu" : menu_comm_set, "caption": "通讯设置", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "menu_alarm", "menu" : menu_alarm, "caption": "故障查询", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "menu_alarm_display", "menu" : menu_alarm_display, "caption": "当前故障", "page" : MENU_ALARM_PAGE, "prev": menu_alarm_curve, "next": menu_alarm_curve, "max_items" : 1}, - {"name" : "menu_alarm_curve", "menu" : menu_alarm_curve, "caption": "曲线故障", "page" : MENU_ADC_CURVE_PAGE, "prev": menu_alarm_display, "next": menu_alarm_display, "max_items" : 1}, - - {"name" : "menu_alarm_history", "menu" : menu_alarm_history, "caption": "故障查询", "page" : MENU_ALARM_PAGE, "max_items" : 1}, - {"name" : "menu_test", "menu" : menu_test, "caption": "保护试验", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "mqtt_pack_alarm", "menu" : mqtt_pack_alarm, "caption": "报警数据", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "mqtt_pack_measure", "menu" : mqtt_pack_measure, "caption": "测量数据", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "menu_data", "menu" : menu_data, "caption": "数据页面", "page" : MENU_DATA_PAGE, "max_items" : 8}, - {"name" : "menu_curve_physical", "menu" : menu_curve_physical, "caption": "物理曲线", "page" : MENU_CURVE_PAGE, "prev": menu_curve_harmonic, "next": menu_curve_adc, "max_items" : 8}, - {"name" : "menu_curve_adc", "menu" : menu_curve_adc, "caption": "ADC曲线", "page" : MENU_ADC_CURVE_PAGE, "prev": menu_curve_physical, "next": menu_curve_harmonic, "max_items" : 8}, - {"name" : "menu_curve_harmonic", "menu" : menu_curve_harmonic, "caption": "谐波曲线", "page" : MENU_HARNOMIC_CURVE_PAGE, "prev": menu_curve_adc, "next": menu_curve_physical, "max_items" : 8}, - {"name" : "calibrate", "menu" : calibrate, "caption": "标定页面", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "menu_switch_cmd", "menu" : menu_switch_cmd, "caption": "通讯操作", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "mqtt_pack_param", "menu" : mqtt_pack_param, "caption": "参数刷新", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - {"name" : "mqtt_video_trigger", "menu" : mqtt_video_trigger, "caption": "视频触发", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, - - {"name" : "mqtt_time_update", "menu" : mqtt_time_update, "caption": "时钟设置", "page" : MENU_DISPLAY_PAGE, "max_items" : 8}, -] - - -# mqtt 故障查询函数 -def func_alarm_query(device : class_modbus_comm_device, alarm_index = 0) : - result = device.protocol.modbus_write_regs(device.comm_addr, 8120, 1, alarm_index) - time.sleep(0.05) - alarm_regs = device.protocol.modbus_read_regs(device.comm_addr, 8121, 20) - if alarm_regs != None : - device.modbus_regs_flush(8121, 20, alarm_regs) - - msg_alarm_dict = device.comm_item_trigger_mqtt_pack(mqtt_pack_alarm) - - err_code = utils.dict_or_object_get_attr(msg_alarm_dict, "AlarmCode", 0) - err_code = int(err_code) - test_code = utils.dict_or_object_get_attr(msg_alarm_dict, "AlarmTest", 0) - test_code = int(test_code) - - - test_value_str = get_alias_value_str("alias_alarm_type", test_code) - if test_value_str == None: - test_value_str = " " - err_code_str = get_alias_value_str("alias_alarm", err_code) - if err_code_str == None: - err_code_str = " " - msg_alarm_dict["AlarmCodeMsg"] = err_code_str - msg_alarm_dict["AlarmTestMsg"] = test_value_str - msg_alarm_dict["index"] = alarm_index - msg : str = json.dumps(msg_alarm_dict, ensure_ascii=False) - - if device.mqtt_thread : - device.mqtt_thread.publish("response/alarm/" + device.unique_name, msg) - -# mqtt action处理函数 -def func_action_process(device : class_modbus_comm_device, menu_item = None, value_str : str = None) : - action_str = utils.dict_or_object_get_attr(menu_item, "action", " ") - mqtt_name = utils.dict_or_object_get_attr(menu_item, "mqtt", " ") - result = None - - if action_str == "SetupTime" : #设置保护器时间 - numbers = re.findall(r'\d+', value_str) - if len(numbers) == 6 : - year = int(numbers[0]) - month = int(numbers[1]) - day = int(numbers[2]) - hour = int(numbers[3]) - minute = int(numbers[4]) - second = int(numbers[5]) - device.protocol.modbus_write_regs(device.comm_addr, 2300, 6, (year, month, day, hour, minute, second)) - pass - if action_str == "calibrate999" : - result = device.protocol.modbus_write_regs(device.comm_addr, 8255, 0x2007) - if action_str == "calibrate0" : - result = device.protocol.modbus_write_regs(device.comm_addr, 8255, 0x2006) - if action_str == "write_bit" or action_str == "test": - comm_str = utils.dict_or_object_get_attr(menu_item, "addr", " ") - reg_addr, bit, reg_count = utils.comm_str_unpack(comm_str) - if reg_count == 1: - command_value = [1] - result = device.write_bit_register(reg_addr, command_value) - - if device.mqtt_thread and result != None: - device.mqtt_thread.publish("response/action/" + device.unique_name, '{"name" : "%s", "result" : %d}'%(mqtt_name, result)) - - -class class_menu_comm_device_config(class_comm_device_config): - def __init__(self): - pass - - #@override get_alias_table - def get_alias_table(self) : - return alias_table - - #@override get_comm_table - def get_comm_table(self) : - return modbus_comm_table, func_comm_table_trigger_check - - #@override get_menu_top - def get_menu_top(self) : - return menu_main - - def get_menu_caption_info(self) : - return menu_caption - - #@override get_mqtt_table - def get_mqtt_table(self) : - return mqtt_topic_subscribe - - def is_gb2312(self) : - return False - -#comm_device_config的名字不要更改, 创建通讯配置类 -comm_device_config = class_menu_comm_device_config() diff --git a/menu_page.py b/menu_page.py deleted file mode 100644 index bb8b38e..0000000 --- a/menu_page.py +++ /dev/null @@ -1,6 +0,0 @@ -#昆仑通态组合页面设计 - -KUNLUN_GRAOUP_PAGE_MAIN = 20 #主选择菜单页面 -KUNLUN_GRAOUP_PAGE_MENU = 5 #文字菜单页面 -KUNLUN_GRAOUP_PAGE_ALARM = 7 #报警页面 -KUNLUN_GRAOUP_PAGE_DEVICE_KD = 21 #馈电页面 diff --git a/menu_utils.py b/menu_utils.py deleted file mode 100644 index e85dd43..0000000 --- a/menu_utils.py +++ /dev/null @@ -1,109 +0,0 @@ -import re -import sys -import inspect -import enum as Enum - -def find_variable_name(value): - frame = inspect.currentframe() - try: - for var_name, var_value in frame.f_back.f_locals.items(): - if var_value is value: - return var_name - finally: - del frame - - -def dict_or_object_get_attr(dict_or_object, name, default_attr) : - if dict_or_object == None or name == None: - return default_attr - - if type(dict_or_object) == dict : - if name in dict_or_object.keys(): - return dict_or_object[name] - return default_attr - - return getattr(dict_or_object, name, default_attr) - -def value_u64_to_s64(value) : - svalue = value - if (svalue >> 63) & 0x1 : - svalue = -((svalue ^ 0xFFFFFFFFFFFFFFFF) + 1) - return svalue - -def value_u32_to_s32(value) : - svalue = value - if (svalue & 0x80000000) : - svalue = -((svalue ^ 0xFFFFFFFF) + 1) - return svalue - -def value_u16_to_s16(value) : - svalue = value - if (svalue & 0x8000) : - svalue = -((svalue ^ 0xFFFF) + 1) - return svalue - -''' -正则表达式 -^:匹配字符串开头。 -$:匹配字符串结尾。 -.:匹配任意字符。 -*:匹配前面的字符零次或多次。 -+:匹配前面的字符一次或多次。 -?:匹配前面的字符零次或一次。 -[]:匹配括号中列举的任意一个字符。 -[^]:匹配除了括号中列举的字符以外的任意一个字符。 -():标记一个子表达式的开始和结束位置。 -\s: 包含空格 -\S: 不包含空格 -\d: 包含数字 -\D: 不包含数字 -''' -def comm_str_unpack(comm_str) : - pattern_bit_regs = "(\d+)\.(\d+)((\s*)#(\s*)(\d+))*" - pattern_regs = "(\d+)((\s*)#(\s*)(\d+))*" - - reg_addr = 0 - reg_count = 0 - bit = -1 - - bit_reg_result = None - reg_result = None - - if comm_str == None : - return reg_addr, bit, reg_count - - #[8000.2 # 3] or [8000.2] - bit_reg_result = re.search(pattern_bit_regs, comm_str) - if bit_reg_result : - match_str = bit_reg_result.string - bit_result_value = re.findall('\d+', match_str) - item_count = len(bit_result_value) - - if item_count >= 2 : - reg_addr = int(bit_result_value[0]) - bit = int(bit_result_value[1]) - if item_count == 3: - reg_count = int(bit_result_value[2]) - else : - reg_count = 1 - - #[8000 # 2] or [8000] - reg_result = None - if bit_reg_result == None: - reg_result = re.search(pattern_regs, comm_str) - - if reg_result != None: - match_str = reg_result.string - reg_result_value = re.findall('\d+', match_str) - item = len(reg_result_value) - - if item >= 1 : - reg_addr = int(reg_result_value[0]) - - if item == 2 : - reg_count = int(reg_result_value[1]) - else : - reg_count = 1 - - return reg_addr, bit, reg_count - diff --git a/mqtt_device.py b/mqtt_device.py deleted file mode 100644 index 84ea794..0000000 --- a/mqtt_device.py +++ /dev/null @@ -1,218 +0,0 @@ -import threading -import time -import string -from threading import Thread -import menu_utils as utils -import paho.mqtt.client as mqtt -from print_color import * - - -#mqtt 消息处理基类, mqtt消息处理 -class class_comm_mqtt_interface : - def __init__(self, name = "mqtt handler"): - self.name = name - - def on_message(self, mqtt_thread, topic, message) : - return - - def on_connect(self, mqtt_thread, userdata, flags, rc) : - return - -#mqtt服务器连接处理 -def mqtt_on_connect(client, userdata, flags, rc): - if rc == 0: - # 连接成功 - print_normal_msg("Mqtt 服务器连接成功") - elif rc == 1: - # 协议版本错误 - print_error_msg("协议版本错误") - elif rc == 2: - # 无效的客户端标识 - print_error_msg("无效的客户端标识") - elif rc == 3: - # 服务器无法使用 - print_error_msg("Mqtt 服务器无法使用") - elif rc == 4: - # 错误的用户名或密码 - print_error_msg("错误的用户名或密码") - elif rc == 5: - # 未经授权 - print_error_msg("未经授权") - - #获取线程类 (class_comm_mqtt_thread) - mqtt_thread : class_comm_mqtt_thread= userdata - unique_object : class_comm_mqtt_interface = None - - #遍历所有unique_object, 通知其 on_connect 事件 - for unique_object in mqtt_thread.unique_object_dict.values() : - if isinstance(unique_object, list) : #unique_object 可能是列表, 所以需要遍历 - for each_object in unique_object: - if hasattr(each_object, "on_connect") : - each_object.on_connect(mqtt_thread, userdata, flags, rc) - elif hasattr(unique_object, "on_connect") : - unique_object.on_connect(mqtt_thread, userdata, flags, rc) - -#mqtt接收到主题, 通过主题中包含的 unique_name, 定位到 uniuqe_object, 并调用 unique_object.on_message 函数 -def mqtt_on_message(client, userdata, message): - #print("mqtt message:", message.topic, message.payload.decode("utf-8")) - - #获取线程类 (class_comm_mqtt_thread) - mqtt_thread : class_comm_mqtt_thread= userdata - - unique_object : class_comm_mqtt_interface = None - for unique_name, search_unique_object in mqtt_thread.unique_object_dict.items() : - if unique_name in message.topic : - unique_object = search_unique_object - break - - #mqtt线程本身无法处理对应的主题消息, 由mqtt 所对应的unique_object处理 - if unique_object != None : - if isinstance(unique_object, list) : #unique_object 可能是列表, 所以需要遍历 - for each_object in unique_object: - if hasattr(each_object, "on_message") : - each_object.on_message(mqtt_thread, message.topic, message.payload) - elif hasattr(unique_object, "on_message") : - unique_object.on_message(mqtt_thread, message.topic, message.payload) - -class class_comm_mqtt_thread(Thread): - def __init__(self, user_name = "admin", password = "admin") : - Thread.__init__(self) - self.client = None - - self.subscribe_list = [] - self.publish_list = [] - self.publish_list_lock = threading.Lock() - self.condition = threading.Condition() - self.stop_request = False - - self.server = "127.0.0.1" - self.port = 1883 - self.user_name = user_name - self.password = password - self.keepalive = 60 - - self.unique_object_dict = {} #key = unique_name, value = device_object - return - - #unique_object: 为unique_object_subscribe_name对应的object, 在回调 - def add_unique_object(self, unique_name : string, unique_object : class_comm_mqtt_interface) : - self.unique_object_dict[unique_name] = unique_object - - #topic 中 需要包含 - def subscribe(self, topic : string) : - if self.is_connect() and self.client: - if topic not in self.subscribe_list : - self.subscribe_list.append(topic) - self.client.subscribe(topic) - - def set_mqtt_server(self, server = "127.0.0.1", port = 1883, keep_alive = 60.0, user_name = "admin", password = "admin") : - self.server = server - self.port = port - self.user_name = user_name - self.password = password - self.keepalive = keep_alive - - #用于判断 mqtt_thread是否已经连接 - def is_connect(self) : - if self.client == None : - return False - return self.client.is_connected() - - def open(self): - try : - self.client = mqtt.Client() - self.client.user_data_set(self) - self.client.on_connect = mqtt_on_connect - self.client.on_message = mqtt_on_message - self.client.username_pw_set(self.user_name, self.password) - self.client.connect(self.server, self.port, self.keepalive) - except Exception as e : - print_error_msg(str(e) + "mqtt_server: ip=%s, port = %d"%(self.server, self.port)) - if self.client: # 如果self.client已经被初始化了,则断开连接 - self.client.disconnect() - self.client = None - return None # 添加返回语句,告知调用者连接失败 - return self.client - - def close(self): - self.stop_request = True - - def publish(self, topic, message) : - if self.is_connect : - self.publish_list_lock.acquire() - self.publish_list.append([topic, message]) - self.publish_list_lock.release() - - self.condition.acquire() - self.condition.notify() - self.condition.release() - return - - def publish_wait(self, topic, message, timeout) : - if self.is_connect : - self.publish_list_lock.acquire() - self.publish_list.insert(0, [topic, message]) - self.publish_list_lock.release() - self.condition.acquire() - self.condition.notify() - self.condition.release() - return - - def run(self): - while self.stop_request == False : - print_warning_msg("mqtt 线程启动, 服务器端口:server = %s:%d"%(self.server, self.port)) - - wait_open_timeout = 0 - self.subscribe_list = [] #取消订阅列表, 连接后重新订阅 - - while self.client == None and self.stop_request == False: - if wait_open_timeout == 0 : - print_warning_msg("mqtt连接中, 服务器端口:server = %s:%d"%(self.server, self.port)) - self.open() - - if self.client == None : - time.sleep(0.1) - wait_open_timeout += 0.1 - if wait_open_timeout >= 5.0 : - wait_open_timeout = 0 - - time.sleep(0.2) - - if self.client : - self.client.loop_start() - time.sleep(0.2) - - while self.stop_request == False and self.client.is_connected() : - topic = None - topic_message = None - - self.publish_list_lock.acquire() - if len(self.publish_list) > 0 : - topic_message = self.publish_list.pop(0) - topic = topic_message[0] - message = topic_message[1] - self.publish_list_lock.release() - - if topic != None and message != None : - self.client.publish(topic, message) - - self.condition.acquire() - if len(self.publish_list) == 0: - self.condition.wait(timeout = 0.1) - self.condition.release() - - self.client.loop_stop() - self.client.disconnect() - self.client = None - - print_warning_msg("mqtt连接断开, 准备重启mqtt连接") - print_error_msg("mqtt 线程停止") - -if __name__ == "__main__": - object_mqtt1 = class_comm_mqtt_interface("object1 handler") - object_mqtt2 = class_comm_mqtt_interface("object2 handler") - global_mqtt_thread = class_comm_mqtt_thread() - global_mqtt_thread.set_mqtt_server(server = "127.0.0.1", port = 1883, keep_alive = 60, user_name="admin", password="admin") - global_mqtt_thread.add_unique_object("object1", object_mqtt1) - global_mqtt_thread.add_unique_object("object2", object_mqtt2) - global_mqtt_thread.start() diff --git a/mqtt_object.py b/mqtt_object.py deleted file mode 100644 index fbbd612..0000000 --- a/mqtt_object.py +++ /dev/null @@ -1,102 +0,0 @@ -import menu_utils as utils -import json -from mqtt_device import class_comm_mqtt_interface, class_comm_mqtt_thread -from device_conf import class_comm_device_config -import string -from enum import Enum -import math -from print_color import * - -#创建mqtt 消息属性字典, -class class_mqtt_info_object (class_comm_mqtt_interface): - def __init__(self, device_name): - class_comm_mqtt_interface.__init__(self) - self.mqtt_dict = {} - - device_config_info = __import__(device_name) - - self.device_config : class_comm_device_config = device_config_info.comm_device_config - self.menu_description = self.device_config.get_menu_caption_info() - - menu_process_list = [] - for item_dict in self.menu_description : - if "menu" in item_dict.keys() : - menu_object = item_dict["menu"] - self.__create_mqtt_dict__(menu_object, menu_process_list) - - #创建mqtt索引, 用于定位mqtt消息相关的菜单属性, 内部函数, 外部不要调用 - def __create_mqtt_dict__(self, menu_object, menu_process_list: list): #创建菜单对应的各项mqtt信息,包含菜单内部的子菜单的各项mqtt信息 - if menu_object == None : - return - if menu_object in menu_process_list : #防止递归进入无限循环 - return - - menu_process_list.append(menu_object) #添加到处理队列中,可以防止menu_object重复处理 - - for menu_item in menu_object : #遍历菜单内部的各个菜单项 - if "mqtt" in menu_item.keys() : #该项菜单具有mqtt属性 - mqtt_info_name = menu_item["mqtt"] #获取mqtt的信息名称, mqtt的消息中包含该信息时,可快速定位该 菜单项 - if mqtt_info_name not in self.mqtt_dict.keys() : #mqtt信息需要具有唯一性, - self.mqtt_dict[mqtt_info_name] = menu_item #把mqtt信息与 菜单项 进行(key, value)绑定. key = mqtt信息, value为菜单项 - else : - print_error_msg("Error, 菜单项有相同的mqtt字段(%s)"%(mqtt_info_name)) - - if "sub_menu" in menu_item.keys() : - sub_menu_name = menu_item["sub_menu"] - if isinstance(sub_menu_name, Enum): - sub_menu_name = sub_menu_name.name - - sub_menu_object = self.search_menu_group_object(sub_menu_name) - self.__create_mqtt_dict__(sub_menu_object, menu_process_list) #递归调用, 直到处理完所有子菜单项 - - #通过菜单名搜索到菜单项 - def search_menu_item(self, mqtt_info_name : string) : - if mqtt_info_name in self.mqtt_dict.keys() : - return self.mqtt_dict[mqtt_info_name] - else : - return None - - #通过菜单名字来查找菜单组对象, 每个菜单组包含若干个菜单项 - def search_menu_group_object(self, menu_group_name) : - menu_group_object = None - for item_dict in self.menu_description: - menu_item_name = utils.dict_or_object_get_attr(item_dict, "name", None) - if menu_item_name == menu_group_name : - menu_group_object = utils.dict_or_object_get_attr(item_dict, "menu", None) - break - return menu_group_object - - -#定义mqtt信息组:所有设备的mqtt信息 都集中于该类 -class class_mqtt_info_object_group(): - def __init__(self): - self.device_mqtt_info_dict : class_mqtt_info_object = {} - - def create_mqtt_info_object(self, device_name) ->class_mqtt_info_object: - try : - mqtt_info_object = None - - if device_name not in self.device_mqtt_info_dict.keys() : - new_mqtt_info = class_mqtt_info_object(device_name) - self.device_mqtt_info_dict[device_name] = new_mqtt_info - mqtt_info_object = self.get_mqtt_info_object(device_name) - except Exception as e: - print_error_msg(str(e)) - mqtt_info_object = None - finally : - return mqtt_info_object - - def get_mqtt_info_object(self, device_name) ->class_mqtt_info_object: - matched_mqtt_info = None - if device_name in self.device_mqtt_info_dict.keys() : - matched_mqtt_info = self.device_mqtt_info_dict[device_name] - - return matched_mqtt_info - - def search_mqtt_menu_item_info(self, device_name, mqtt_info_name) : - if mqtt_info_name in self.device_mqtt_info_dict.keys() : - mqtt_info_object : class_mqtt_info_object = self.device_mqtt_info_dict[device_name] - menu_item = mqtt_info_object.search_menu_item(mqtt_info_name) - return menu_item - return None - diff --git a/print_color.py b/print_color.py deleted file mode 100644 index 3738742..0000000 --- a/print_color.py +++ /dev/null @@ -1,41 +0,0 @@ -from colorama import init, Fore, Back, Style -from threading import Lock -import datetime - -init() # 初始化colorama -print_mutex = Lock() - -def print_normal_msg(*args, **kwargs) : - current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - print_mutex.acquire() - print(current_time, *args, **kwargs, end='') - print(Style.RESET_ALL) - print_mutex.release() - -def print_warning_msg(*args, **kwargs) : - current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - print_mutex.acquire() - print(current_time, Fore.LIGHTMAGENTA_EX, *args, **kwargs, end='') - print(Style.RESET_ALL) - print_mutex.release() - -def print_inform_msg(*args, **kwargs) : - current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - print_mutex.acquire() - print(current_time, Fore.YELLOW, *args, **kwargs, end='') - print(Style.RESET_ALL) - print_mutex.release() - -def print_error_msg(*args, **kwargs) : - current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - print_mutex.acquire() - print(current_time, Fore.RED, *args, **kwargs, end='') - print(Style.RESET_ALL) - print_mutex.release() - -def print_debug_msg(*args, **kwargs) : - current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - print_mutex.acquire() - print(current_time, Fore.BLUE, *args, **kwargs, end='') - print(Style.RESET_ALL) - print_mutex.release() \ No newline at end of file