import logging import os import time import subprocess from tkinter import E from appium import webdriver from appium.options.android import UiAutomator2Options from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import TimeoutException, NoSuchElementException from page_objects.download_tabbar_page import DownloadTabbarPage from page_objects.measure_tabbar_page import MeasureTabbarPage from page_objects.section_mileage_config_page import SectionMileageConfigPage from page_objects.upload_config_page import UploadConfigPage from page_objects.more_download_page import MoreDownloadPage from page_objects.screenshot_page import ScreenshotPage import globals.driver_utils as driver_utils # 导入驱动工具模块 import globals.global_variable as global_variable from page_objects.login_page import LoginPage import globals.apis as apis import globals.create_link as create_link class DeviceAutomation: # def __init__(self, device_id=None): # # 如果没有提供设备ID,则自动获取 # if device_id is None: # self.device_id = driver_utils.get_device_id() # else: # self.device_id = device_id # # 初始化权限 # if driver_utils.grant_appium_permissions(self.device_id): # logging.info(f"设备 {self.device_id} 授予Appium权限成功") # else: # logging.warning(f"设备 {self.device_id} 授予Appium权限失败") # # 确保Appium服务器正在运行,不在运行则启动 # if not driver_utils.check_server_status(4723): # driver_utils.start_appium_server() # # 初始化Appium驱动和页面对象 # self.init_driver() # # 创建测试结果目录 # self.results_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'test_results') def __init__(self, driver=None, wait=None, device_id=None): self.driver = driver self.wait = wait self.device_id = device_id # 初始化权限 if driver_utils.grant_appium_permissions(self.device_id): logging.info(f"设备 {self.device_id} 授予Appium权限成功") else: logging.warning(f"设备 {self.device_id} 授予Appium权限失败") # 确保Appium服务器正在运行,不在运行则启动 if not driver_utils.check_server_status(4723): driver_utils.start_appium_server() # 初始化Appium驱动和页面对象 self.init_driver() # @staticmethod # def get_device_id() -> str: # """ # 获取设备ID,优先使用已连接设备,否则使用全局配置 # """ # try: # # 检查已连接设备 # result = subprocess.run( # ["adb", "devices"], # capture_output=True, # text=True, # timeout=10 # ) # target_port = "4723" # for line in result.stdout.strip().split('\n')[1:]: # if line.strip() and "device" in line and "offline" not in line: # device_id = line.split('\t')[0] # # 检查是否为无线设备且端口为4723 # if ':' in device_id: # ip_port = device_id.split(':') # if len(ip_port) == 2 and ip_port[1] == target_port: # logging.info(f"找到目标无线设备(端口{target_port}): {device_id}") # global_variable.GLOBAL_DEVICE_ID = device_id # return device_id # # 如果没有找到端口4723的设备,找其他无线设备 # for line in result.stdout.strip().split('\n')[1:]: # if line.strip() and "device" in line and "offline" not in line: # device_id = line.split('\t')[0] # # 检查是否为无线设备(任何端口) # if ':' in device_id and device_id.split(':')[-1].isdigit(): # logging.info(f"未找到端口{target_port}的设备,使用其他无线设备: {device_id}") # global_variable.GLOBAL_DEVICE_ID = device_id # return device_id # # 如果没有任何无线设备,找有线设备 # for line in result.stdout.strip().split('\n')[1:]: # if line.strip() and "device" in line and "offline" not in line: # device_id = line.split('\t')[0] # logging.info(f"未找到无线设备,使用有线设备: {device_id}") # global_variable.GLOBAL_DEVICE_ID = device_id # return device_id # logging.error("未找到任何可用设备") # return None # except Exception as e: # logging.warning(f"设备检测失败: {e}") # # 使用全局配置 # device_id = global_variable.GLOBAL_DEVICE_ID # logging.info(f"使用全局配置设备: {device_id}") # return device_id def init_driver(self): """初始化Appium驱动""" try: # # 使用全局函数初始化驱动 # self.driver, self.wait = driver_utils.init_appium_driver(self.device_id) # 初始化页面对象 logging.info(f"设备 {self.device_id} 开始初始化页面对象") self.login_page = LoginPage(self.driver, self.wait) self.download_tabbar_page = DownloadTabbarPage(self.driver, self.wait, self.device_id) self.measure_tabbar_page = MeasureTabbarPage(self.driver, self.wait,self.device_id) self.section_mileage_config_page = SectionMileageConfigPage(self.driver, self.wait, self.device_id) self.upload_config_page = UploadConfigPage(self.driver, self.wait, self.device_id) self.more_download_page = MoreDownloadPage(self.driver, self.wait,self.device_id) self.screenshot_page = ScreenshotPage(self.driver, self.wait, self.device_id) logging.info(f"设备 {self.device_id} 所有页面对象初始化完成") # 检查应用是否成功启动 if driver_utils.is_app_launched(self.driver): logging.info(f"设备 {self.device_id} 沉降观测App已成功启动") else: logging.warning(f"设备 {self.device_id} 应用可能未正确启动(init_driver)") driver_utils.launch_app_manually(self.driver) except Exception as e: logging.error(f"设备 {self.device_id} 初始化驱动失败: {str(e)}") raise def run_automation(self): """根据当前应用状态处理相应的操作""" try: max_retry = 3 # 限制最大重试次数 retry_count = 0 while retry_count < max_retry: login_btn_exists = self.login_page.is_login_page() if not login_btn_exists: logging.error(f"设备 {self.device_id} 未知应用状态,无法确定当前页面,跳转到登录页面") if self.login_page.navigate_to_login_page(self.driver, self.device_id): logging.info(f"设备 {self.device_id} 成功跳转到登录页面") else: logging.error(f"设备 {self.device_id} 跳转到登录页面失败") retry_count += 1 continue # 处理登录页面状态 logging.info(f"设备 {self.device_id} 检测到登录页面,执行登录操作") max_retries_login = 3 login_success = False for attempt in range(max_retries_login + 1): if self.login_page.login("wangshun"): login_success = True break else: if attempt < max_retries_login: logging.warning(f"设备 {self.device_id} 登录失败,准备重试 ({attempt + 1}/{max_retries_login})") time.sleep(2) # 等待2秒后重试 else: logging.error(f"设备 {self.device_id} 登录失败,已达到最大重试次数") if login_success: break elif retry_count == max_retry-1: logging.error(f"设备 {self.device_id} 处理登录页面失败,已达到最大重试次数") return False else: retry_count += 1 # login_btn_exists = self.login_page.is_login_page() # if not login_btn_exists: # logging.error(f"设备 {self.device_id} 未知应用状态,无法确定当前页面,跳转到登录页面") # if self.login_page.navigate_to_login_page(self.driver, self.device_id): # logging.info(f"设备 {self.device_id} 成功跳转到登录页面") # return self.run_automation() # 递归调用处理登录后的状态 # else: # logging.error(f"设备 {self.device_id} 跳转到登录页面失败") # return False # # 处理登录页面状态 # logging.info(f"设备 {self.device_id} 检测到登录页面,执行登录操作") # max_retries = 1 # login_success = False # for attempt in range(max_retries + 1): # if self.login_page.login(): # login_success = True # break # else: # if attempt < max_retries: # logging.warning(f"设备 {self.device_id} 登录失败,准备重试 ({attempt + 1}/{max_retries})") # time.sleep(2) # 等待2秒后重试 # else: # logging.error(f"设备 {self.device_id} 登录失败,已达到最大重试次数") # if not login_success: # return False logging.info(f"设备 {self.device_id} 登录成功,继续执行更新操作") time.sleep(1) # 执行更新操作 if not self.download_tabbar_page.download_tabbar_page_manager(): logging.error(f"设备 {self.device_id} 更新操作执行失败") return False task_count = 0 max_tasks = 1 # 最大任务数量,防止无限循环 while task_count < max_tasks: # 获取测量任务 logging.info(f"设备 {self.device_id} 获取测量任务 (第{task_count + 1}次)") # task_data = apis.get_measurement_task() # logging.info(f"设备 {self.device_id} 获取到的测量任务: {task_data}") task_data = { "id": 39, "user_name": "czsczq115ykl", "name": "czsczq115ykl", "line_num": "L179451", "line_name": "CDWZQ-2标-资阳沱江特大桥-23-35-山区", "remaining": "0", "status": 1 } if not task_data: logging.info(f"设备 {self.device_id} 未获取到状态为1的测量任务,等待后重试") time.sleep(1) # 等待1秒后重试 break # continue # 设置全局变量 global_variable.GLOBAL_CURRENT_PROJECT_NAME = task_data.get('line_name', '') global_variable.GLOBAL_LINE_NUM = task_data.get('line_num', '') logging.info(f"设备 {self.device_id} 当前要处理的项目名称:{global_variable.GLOBAL_CURRENT_PROJECT_NAME}") # 执行测量操作 # logging.info(f"设备 {self.device_id} 开始执行测量操作") if not self.measure_tabbar_page.measure_tabbar_page_manager(): logging.error(f"设备 {self.device_id} 测量操作执行失败") # # 返回到测量页面 # self.driver.back() # self.check_and_click_confirm_popup_appium() continue # 继续下一个任务 logging.info(f"设备 {self.device_id} 测量页面操作执行成功") # 在测量操作完成后执行断面里程配置 logging.info(f"设备 {self.device_id} 开始执行断面里程配置") if not self.section_mileage_config_page.section_mileage_config_page_manager(): logging.error(f"设备 {self.device_id} 断面里程配置执行失败") continue # 继续下一个任务 # 任务完成后短暂等待 logging.info(f"设备 {self.device_id} 第{task_count}个任务完成") task_count += 1 logging.info(f"设备 {self.device_id} 已完成{task_count}个任务,结束打数据流程") if task_count == 0: logging.error(f"没有完成打数据的线路,结束任务") return False # GLOBAL_TESTED_BREAKPOINT_LIST 把已打完的写入日志文件 # with open(os.path.join(self.results_dir, "打数据完成线路.txt"), "w", encoding='utf-8') as f: # for bp in global_variable.GLOBAL_TESTED_BREAKPOINT_LIST: # f.write(f"{bp}\n") return task_count > 0 except Exception as e: logging.error(f"设备 {self.device_id} 处理应用状态时出错: {str(e)}") return False # 主执行逻辑 if __name__ == "__main__": create_link.setup_adb_wireless() automation = None try: automation = DeviceAutomation() success = automation.run_automation() if success: logging.info(f"设备 {automation.device_id} 自动化流程执行成功") else: logging.error(f"设备 {automation.device_id} 自动化流程执行失败") except Exception as e: logging.error(f"设备执行出错: {str(e)}") finally: if automation: driver_utils.safe_quit_driver(automation.driver, automation.device_id)