docs: doc/ 全量重整——按现状重写并建立文档索引;项目统一更名 auto_control
背景:文档长期落后于代码(Tab 数、任务类型、接口示例等多处与现状不符), 且信息分散重复。这次按当前代码状态逐篇重写,并建立统一的文档体系。 新增 - doc/README.md:文档总索引(文档地图 / 推荐阅读路径 / **文档维护约定**) - doc/DATA_MODEL.md:数据模型(7 张模型表 + 5 张非模型表、迁移机制、app_meta 键、 数据目录、备份覆盖清单与双向自检) - doc/AI_CONSOLE.md:AI 控制台机制(会话与 SSE、经验库/动作库蒸馏与召回、巡检、 Markdown 渲染、推理链、token 统计、故障排查) 重写(按现状,去掉过时与重复) - README.md:7 个 Tab、18 种步骤、设备生命周期、调度/窗口语义、常见问题;修掉 「6 个 Tab / 分组为顶级 Tab」等过时内容与损坏的目录树 - doc/ARCHITECTURE.md:补启动装配顺序(import 期副作用、A~G 七阶段)、线程与锁清单、 设备状态机、调度全链路、前端结构与实时通道、设计决策、**已知缺陷与踩坑清单**、扩展点 - doc/API.md:按蓝图重建「接口总索引」(107 条路由含鉴权)+ 分域详细说明 + 非 JSON 响应汇总 + 错误分支速查 - doc/TASK_DEV.md:18 种步骤全表(参数/默认值/语义)、容器与公共参数、 选择器与 XPath 序号语义、抓取器建议规则、新增任务类型骨架 - doc/DEPLOY.md:容器入口 start.sh 三件事、发布流程与检查清单、备份覆盖红线、 按现象分类的故障排查 - doc/DEVELOPMENT.md:流程/红线/本地开发/**测试与写测试的约定**/配置速查/文档同步 - doc/MCP.md:19 个工具的参数级清单、坐标空间、写门控三连、安全与审计 - doc/MCP_DESIGN.md、doc/AI_TASK_GEN.md:标注设计 vs 实现现状,补交叉链接 - doc/backlog/TODO.md:新增「已知缺陷」小节(含复现与影响)+ 已完成留档 - .env.example:按代码实际读取的键重写(补 USB/DISCOVERY/MCP/AGENT,删死配置) 其它 - 项目名统一 auto_control:README/文档/scripts/pack.py 产物名;代码内的 doc 章节引用(templates/admin/monitor.html)同步更新 - 校验:16 篇文档 156 条相对链接全部可解析;文档中的关键数字与代码核对一致 (19 个 MCP 工具 / 18 种步骤 / 12 张备份表 / 1 种任务类型)
This commit is contained in:
@@ -1,23 +1,58 @@
|
||||
# 设备自动化后台(platform-tools)
|
||||
# auto_control — Android 多设备自动化任务平台
|
||||
|
||||
基于 **uiautomator2 + Flask + 自建设备池** 的 Android 多设备自动化任务执行平台(已摘除 OpenSTF 依赖)。
|
||||
基于 **uiautomator2 + Flask + 自建设备池** 的 Android 多设备自动化平台(已摘除 OpenSTF 依赖,见 [doc/STF_REMOVAL.md](doc/STF_REMOVAL.md))。
|
||||
|
||||
提供 Web 管理后台,支持多设备并发任务执行、定时调度、设备分组管理、设备池管理(新增/停用/删除/型号采集)、APK 批量安装、网页远程看屏(MJPEG 实时流 + 触控)、UI 元素抓取等功能。内置通用步骤任务(可视化步骤编辑器编排,覆盖任意 App 的操作),可扩展专属任务类型。
|
||||
一台机器上统管一批 Android 设备:定时/手动下发任务、并发执行、实时看屏与远程触控、元素抓取与步骤编排、APK 批量安装、数据备份导出/导入;并通过 **MCP** 把手机控制能力开放给外部 AI(数字员工)。
|
||||
|
||||
```
|
||||
┌──────────── Web 管理后台(单页应用,:18050)────────────┐
|
||||
浏览器 ────────────▶ │ 监控 │ 任务 │ 日志 │ 用户 │ 工具 │ AI 控制台 │ 系统 │
|
||||
└───────────────────────┬─────────────────────────────────┘
|
||||
│ Flask 蓝图(web/)
|
||||
┌───────────────────────▼──────┐ ┌──────────────────────┐
|
||||
│ 调度 TaskManager │ │ AI Agent(mcp_agent)│
|
||||
│ 设备池 device_pool │ └──────────┬───────────┘
|
||||
│ Worker(每设备一线程) │ │ MCP :8033
|
||||
└───────┬──────────────┬───────┘ ┌──────────▼───────────┐
|
||||
│ │ │ MCP Server(de_* 工具)│
|
||||
adb 直连 uiautodev └──────────┬───────────┘
|
||||
IP:5555 / USB :20242(抓元素) │
|
||||
▼ ▼
|
||||
Android 设备 ◀──────────────────────── Android 设备
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 目录
|
||||
|
||||
- [核心能力](#核心能力)
|
||||
- [快速上手](#快速上手)
|
||||
- [项目结构](#项目结构)
|
||||
- [核心概念](#核心概念)
|
||||
- [配置说明](#配置说明)
|
||||
- [Web 管理后台](#web-管理后台)
|
||||
- [任务系统](#任务系统)
|
||||
- [日志系统](#日志系统)
|
||||
- [常用脚本](#常用脚本)
|
||||
- [任务与步骤](#任务与步骤)
|
||||
- [AI 与 MCP](#ai-与-mcp)
|
||||
- [配置说明](#配置说明)
|
||||
- [日志](#日志)
|
||||
- [常见问题](#常见问题)
|
||||
- [更多文档](#更多文档)
|
||||
- [文档索引](#文档索引)
|
||||
|
||||
---
|
||||
|
||||
## 核心能力
|
||||
|
||||
| 能力 | 说明 |
|
||||
|------|------|
|
||||
| **多设备并发任务** | 每设备一个 Worker 线程;同一设备同时只跑一个任务(可配置"抢占"打断其他任务) |
|
||||
| **设备池** | SQLite 清单 + adb 在线状态;支持手工添加、网段自动发现、一键重连、型号采集、启用/停用 |
|
||||
| **任务调度** | 手动 / cron 定时 / 定时启停;运行窗口;失败重试(含端口耗尽类的长退避) |
|
||||
| **步骤编辑器** | 可视化拖拽编排 18 种步骤(含循环/条件/OCR),可打包成"自定义动作"复用 |
|
||||
| **元素抓取** | 拉取设备 UI 元素树 → 点选回填选择器;支持"点一下"与"测选择器"真机验证 |
|
||||
| **实时看屏** | MJPEG 实时流 + 点击/滑动/按键/文字输入;全屏监控大屏(`/wall`) |
|
||||
| **应用管理** | APK 上传/解析/批量安装;设备已装应用与版本查询;剪贴板注入 |
|
||||
| **AI 控制台** | 用自然语言驱动 AI 操作指定设备(MCP 工具 + 截图),流式输出、Markdown 渲染、推理链折叠、token 统计;成功操作自动沉淀「经验库 / 动作库」并在相似任务中召回 |
|
||||
| **MCP 接入** | 19 个 `de_*` 工具,把手机控制开放给外部 AI;写操作有开关、设备忙时拒绝、全量审计 |
|
||||
| **备份导出/导入** | 一键导出 zip(库快照 + manifest + 可选 APK),导入前校验预览、自动预备份、重启生效 |
|
||||
|
||||
---
|
||||
|
||||
@@ -26,9 +61,8 @@
|
||||
### 环境要求
|
||||
|
||||
- **Python 3.10+**(推荐 3.12)
|
||||
- **Windows / Linux / macOS**均可(adb 二进制需放对应平台版本到 `bin/adb/`)
|
||||
- 设备需开启 **USB 调试**(USB 连上后 `adb tcpip 5555` 转网络调试),并加入 Tailscale 获得 `100.100.10.x` IP
|
||||
- 新增设备在后台「工具 → 设备池管理」添加 `IP:5555`(自动连接,任务运行时 u2 自动推送 atx-agent)
|
||||
- Windows / Linux / macOS 均可(`bin/adb/` 需放对应平台的 adb 二进制)
|
||||
- 设备开启 **USB 调试**;网络调试设备建议 `adb tcpip 5555` 并接入同一网络(本项目生产环境走 Tailscale `100.100.10.x`,见 [doc/DEPLOY.md](doc/DEPLOY.md))
|
||||
|
||||
### 三步启动
|
||||
|
||||
@@ -36,403 +70,327 @@
|
||||
# 1. 安装依赖
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 2. 修改配置(可选):USB 设备在 220 上时配置 USB_ADB_HOST/PORT(默认 100.100.10.1:5037 已可用)
|
||||
# 密钥类配置放 .env(WEB_SECRET_KEY / TAILSCALE_API_KEY)
|
||||
# 2. 配置(可选):把 .env.example 复制成 .env,至少填 WEB_SECRET_KEY
|
||||
# 密钥类配置一律放 .env(不入 git)
|
||||
|
||||
# 3. 启动 Web 后台
|
||||
# 3. 启动
|
||||
python web_server.py
|
||||
```
|
||||
|
||||
启动后访问 **http://localhost:18050/**,默认账号 `admin` / `admin123`。
|
||||
启动后访问 **http://localhost:18050/**,默认账号 `admin` / `admin123`(**首次登录请立即改密**)。
|
||||
|
||||
### 验证启动
|
||||
|
||||
控制台看到以下日志即表示启动成功:
|
||||
|
||||
```
|
||||
[INFO] [core.worker] 心跳看门狗已启动
|
||||
[INFO] [core.tm] 从数据库加载 X 个分组, X 个任务
|
||||
[INFO] [web] uiautodev 服务已启动 (PID=...)
|
||||
[INFO] [web] 管理后台: http://localhost:18050/ (admin/admin123)
|
||||
[INFO] [web] 设备池预连接完成: X 台在线
|
||||
[INFO] [web] 启动服务: http://localhost:18050/
|
||||
```
|
||||
|
||||
### 首次使用流程
|
||||
### 首次使用
|
||||
|
||||
1. **登录后台** → 用 `admin/admin123` 登录,建议立即修改密码
|
||||
2. **添加设备** → "工具 → 设备池管理"添加设备(serial 形如 `100.100.10.20:5555`,自动连接并采集型号)
|
||||
3. **查看设备** → 首页"监控"Tab 展示设备池状态(在线/型号/任务)
|
||||
4. **创建分组**(可选)→ "分组"Tab 按批次/项目给设备分组
|
||||
5. **创建任务** → "任务"Tab 新建任务,选择任务类型、目标设备、参数、调度
|
||||
6. **执行任务** → 任务列表点"立即执行",或在"监控"Tab 勾选设备批量操作(亮屏/息屏/停止)
|
||||
7. **查看日志** → "日志"Tab 实时查看运行日志
|
||||
1. **登录** → `admin/admin123`,改密
|
||||
2. **加设备** → 「工具 → 设备池管理」添加 `IP:5555`(自动连接 + 采集型号);也可用「设备自动发现」扫描网段后确认入池
|
||||
3. **看设备** → 「监控」页设备表(在线/型号/任务/进度/前台 App)
|
||||
4. **建任务** → 「任务 → 任务计划 → 新建任务」(只有 `generic_steps` 一种类型)→ 拖步骤 → 选目标设备 → 保存
|
||||
5. **跑任务** → 任务行「执行」,或在「任务」/「监控」页操作
|
||||
6. **看日志** → 「日志」页按模块实时查看
|
||||
|
||||
---
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
platform-tools/
|
||||
├── config.py # 根配置(部署配置统一从 .env 读,模板见 .env.example)
|
||||
├── web_server.py # Flask 入口(app 装配 + 蓝图注册 + 启动,193 行)
|
||||
├── web/ # Web 层蓝图包(按功能域拆分,路由都在这里)
|
||||
│ ├── auth.py # 登录/CSRF/权限装饰器/页面路由(/、/wall)
|
||||
│ ├── monitor.py # 状态/运行控制/设备操作/远程看屏
|
||||
│ ├── tasks_api.py # 任务计划/分组/自定义动作/元素抓取
|
||||
│ ├── admin_api.py # 用户管理/日志
|
||||
│ ├── tools_api.py # adb 终端/剪贴板注入/应用版本
|
||||
│ ├── devices_api.py # 设备池管理
|
||||
│ ├── apks_api.py # 应用管理
|
||||
│ ├── tailscale_api.py # Tailscale 管理
|
||||
│ ├── common.py # 跨模块共享工具(合并设备列表/屏幕状态)
|
||||
│ └── context.py # 共享对象注入(mgr/apk_mgr/device_pool)
|
||||
├── requirements.txt # Python 依赖清单
|
||||
auto_control/
|
||||
├── config.py # 程序级配置常量(部署配置从 .env 读,模板 .env.example)
|
||||
├── web_server.py # 入口:app 装配 + 蓝图注册 + 恢复消费 + 拉起 uiautodev + 启动
|
||||
├── requirements.txt # 依赖清单
|
||||
│
|
||||
├── core/ # 核心基础设施层
|
||||
│ ├── logger.py # 统一日志(分文件、10MB 滚动)
|
||||
│ ├── device_pool.py # 设备池(SQLite 清单 + adb 在线状态 + 型号采集)
|
||||
│ ├── adb_helper.py # adb 命令封装(全局锁,绝不 kill-server)
|
||||
│ ├── device_worker.py # BaseWorker 基类 + 设备生命周期 + 心跳看门狗
|
||||
│ ├── task_manager.py # TaskManager 调度器 + 前台App扫描器
|
||||
│ ├── u2_helper.py # uiautomator2 通用辅助函数
|
||||
│ ├── uiauto_helper.py # uiautodev 元素抓取客户端
|
||||
│ ├── apk_manager.py # APK 上传/解析/批量安装
|
||||
│ ├── ocr.py # 屏幕 OCR(RapidOCR,条件判断 OCR 选择器)
|
||||
│ ├── ssh_client.py # SSH 统一执行(paramiko 纯密码 / 免密密钥,预留运维用)
|
||||
│ ├── tailscale_client.py # Tailscale API v2 客户端
|
||||
│ ├── models.py # SQLAlchemy 数据模型 + 数据库初始化
|
||||
│ └── actions/ # 全局 Action 框架
|
||||
├── web/ # Web 层(蓝图包,路由都在这里,全部无 url_prefix)
|
||||
│ ├── auth.py # 登录/登出/CSRF/权限装饰器/页面路由(/、/wall)
|
||||
│ ├── monitor.py # 设备状态/运行控制/设备操作/远程看屏(MJPEG、点击、按键)
|
||||
│ ├── tasks_api.py # 任务计划/分组/自定义动作/元素抓取/步骤测试
|
||||
│ ├── admin_api.py # 用户管理/日志
|
||||
│ ├── tools_api.py # adb 终端/剪贴板注入/应用版本查询
|
||||
│ ├── devices_api.py # 设备池管理 + 自动发现
|
||||
│ ├── apks_api.py # APK 上传/安装/删除
|
||||
│ ├── tailscale_api.py # Tailscale 管理(改名/授权/密钥/IP/auth key)
|
||||
│ ├── agent_api.py # AI 控制台(会话/SSE/经验库/动作库/巡检)
|
||||
│ ├── system_api.py # 系统数据备份导出/导入
|
||||
│ ├── common.py # 跨模块共享工具(合并设备列表、屏幕状态)
|
||||
│ └── context.py # 共享对象注入(mgr / apk_mgr / device_pool)
|
||||
│
|
||||
├── tasks/ # 任务定义层(每个 App 一个子包)
|
||||
│ ├── __init__.py # 全局任务注册表
|
||||
│ ├── base.py # BaseTask 基类 + @register_task 装饰器
|
||||
│ └── generic/ # 通用步骤任务(可视化编辑器编排,当前唯一任务类型)
|
||||
│ └── task.py # 步骤执行引擎(open_app/click/swipe/if_el...)
|
||||
├── core/ # 基础设施层
|
||||
│ ├── models.py # SQLAlchemy 模型 + 建表 + 版本化迁移 + 旧 JSON 迁移
|
||||
│ ├── device_pool.py # 设备池(清单/在线状态/型号)
|
||||
│ ├── device_worker.py # BaseWorker + 设备生命周期 + 心跳看门狗 + 全局状态表
|
||||
│ ├── task_manager.py # 调度器:分组/任务/APScheduler/重试/运行控制
|
||||
│ ├── adb_helper.py # adb 命令封装(全局锁,红线:绝不 kill-server)
|
||||
│ ├── device_discovery.py # 网段扫描发现设备 → 待连接池
|
||||
│ ├── u2_helper.py # uiautomator2 通用辅助(等首页/安全点击等)
|
||||
│ ├── uiauto_helper.py # uiautodev 客户端(元素树 + XPath 建议)
|
||||
│ ├── ocr.py # 屏幕 OCR(RapidOCR,条件判断用)
|
||||
│ ├── clipboard_helper.py # 剪贴板注入(ClipInject 通道)
|
||||
│ ├── apk_manager.py # APK 上传/解析/批量安装
|
||||
│ ├── system_backup.py # 数据备份导出/导入(重启生效)
|
||||
│ ├── tailscale_client.py # Tailscale API v2 客户端
|
||||
│ ├── ssh_client.py # SSH 封装(当前无人调用,预留)
|
||||
│ ├── logger.py # 分文件日志(core/task/web/action)
|
||||
│ └── actions/ # 全局 Action 框架(BaseAction + 注册器)
|
||||
│
|
||||
├── templates/admin/ # 前端页面
|
||||
│ ├── monitor.html # 单页应用(监控/任务/分组/日志/用户/工具)
|
||||
│ └── login.html # 登录页
|
||||
├── tasks/ # 任务定义层
|
||||
│ ├── base.py # BaseTask + _TASK_TYPES + register_task
|
||||
│ └── generic/ # 通用步骤任务(task_type=generic_steps,当前唯一类型)
|
||||
│ └── task.py # STEP_TYPES(18 种步骤)+ Worker + 执行器
|
||||
│
|
||||
├── static/admin/ # 前端 JS 模块(monitor.html 按依赖顺序加载)
|
||||
│ ├── base.js # 通用基础:API/CSRF/权限/Tab切换/子分栏/模态框
|
||||
│ ├── list.js # 统一列表组件(搜索+分页+排序)
|
||||
│ ├── monitor.js # 监控页(设备表/截图/异常汇总)
|
||||
│ ├── editor.js # 步骤编辑器(拖拽/条件判断/元素抓取)
|
||||
│ ├── tasks.js # 任务 Tab + 自定义动作
|
||||
│ ├── tools.js # 工具 Tab(剪贴板/设备池管理/adb终端/Tailscale/远程看屏)
|
||||
│ ├── apps.js # 工具 Tab-应用管理(APK/设备已装应用)
|
||||
│ ├── admin.js # 管理 Tab(分组/日志/用户)+ 初始化
|
||||
├── mcp_server/ # MCP Server(19 个 de_* 工具,:8033)
|
||||
│ ├── mcp_server.py # 工具定义 + 平台登录 + 门控
|
||||
│ ├── platform_client.py # 平台 HTTP 客户端(复用 Web 账号)
|
||||
│ ├── direct_ops.py # 直连设备的 adb/u2 操作
|
||||
│ ├── audit.py # 调用审计(JSON Lines)
|
||||
│ └── config.py # MCP_* 环境变量
|
||||
│
|
||||
├── mcp_agent/ # AI Agent 编排层(OpenAI 兼容模型 → MCP 工具)
|
||||
│ ├── agent.py # Agent:流式循环 + 工具调用 + 截图 + token 统计
|
||||
│ ├── config.py # AGENT_* 环境变量
|
||||
│ └── cli.py # 命令行入口
|
||||
│
|
||||
├── templates/admin/ # 页面
|
||||
│ ├── monitor.html # 主单页应用(7 个顶级 Tab + 模态框 + 内联样式)
|
||||
│ ├── login.html # 登录页
|
||||
│ └── wall.html # 监控大屏(独立页面,自包含)
|
||||
├── static/admin/ # 前端 JS(11 个文件,按顺序同步加载,见下)
|
||||
├── static/fonts/ # 自托管字体(Bricolage Grotesque + IBM Plex Mono)
|
||||
│
|
||||
├── data/
|
||||
│
|
||||
├── data/ # 运行时数据
|
||||
│ ├── users.db # SQLite(用户/分组/任务/自定义动作/APK记录)
|
||||
│ └── apks/ # 上传的 APK 文件存储
|
||||
│
|
||||
├── logs/ # 日志文件(自动生成,10MB 滚动保留 5 份)
|
||||
├── bin/adb/ # adb 可执行文件(Windows: adb.exe + dll)
|
||||
├── scripts/ # 实用脚本
|
||||
│ ├── pack.py # 打包项目为 zip(排除运行时产物)
|
||||
│ └── supervise.sh # 进程守护(崩溃自动重启)
|
||||
└── doc/ # 项目文档
|
||||
├── API.md # API 文档
|
||||
├── ARCHITECTURE.md # 架构详解
|
||||
├── DEPLOY.md # 部署指南
|
||||
├── DEVELOPMENT.md # 开发指南
|
||||
└── TASK_DEV.md # 任务开发指南(新增 App 任务模板)
|
||||
├── ARCHITECTURE.md # 架构详解
|
||||
├── DEPLOY.md # 部署指南
|
||||
└── API.md # API 接口文档
|
||||
├── data/ # 运行时数据(不入 git)
|
||||
│ ├── users.db # SQLite 主库
|
||||
│ ├── apks/ # 上传的 APK
|
||||
│ ├── backups/ # 导出 zip / 预恢复快照
|
||||
│ ├── restore_staging/ # 导入暂存(TTL 30 分钟)
|
||||
│ └── restore_pending/ # 待重启生效的恢复任务
|
||||
├── logs/ # 日志(10MB 滚动,保留 5 份)
|
||||
├── bin/adb/ # adb 二进制
|
||||
├── scripts/ # pack.py / start.sh / supervise.sh / regression_test.py
|
||||
└── doc/ # 完整文档(入口 → doc/README.md)
|
||||
```
|
||||
|
||||
前端 JS 加载顺序(`templates/admin/monitor.html` 底部,全部为全局脚本,无模块隔离):
|
||||
|
||||
```
|
||||
base.js → markdown.js → list.js → monitor.js → editor.js → tasks.js
|
||||
→ tools.js → apps.js → admin.js → agent.js → system.js
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 核心概念
|
||||
|
||||
### 设备生命周期
|
||||
### 设备与 Worker
|
||||
|
||||
```
|
||||
设备池选定设备(TaskManager._running 内存锁保证互斥)
|
||||
↓
|
||||
IP:5555 → adb connect 直连;USB(serial 无冒号)→ 本机 adb 或 220 远程 adb server
|
||||
↓
|
||||
u2.connect(连接 uiautomator2,自动推送 atx-agent)
|
||||
↓
|
||||
Worker.run_task(执行业务逻辑)
|
||||
↓
|
||||
释放(不 disconnect,遵守共享 adb transport 红线)
|
||||
```
|
||||
一台设备对应一个 `Worker` 线程(`core/device_worker.py` 的 `BaseWorker`)。基类封装了设备获取、adb/u2 连接(带超时保护)、状态上报、异常分类、停止信号、心跳看门狗;子类只实现 `run_task(d)`。
|
||||
|
||||
> 单实例部署下互斥由调度器内存锁保证;多实例场景可扩展 SQLite 行锁(见 doc/STF_REMOVAL.md 阶段 4)。
|
||||
执行链路:`设备池选定 → adb connect 直连(IP:5555)或经 220 远程 adb server(USB)→ u2.connect(自动推送 atx-agent)→ run_task → 释放(不断开连接)`。
|
||||
|
||||
### Worker — 单设备执行线程
|
||||
**同一设备同时只允许一个 Worker**:由 `TaskManager._running` 内存锁保证;任务可开 `preempt` 抢占(先停掉正在跑的任务再接管,结束后归还)。
|
||||
|
||||
每台设备对应一个 `Worker` 线程,继承 `BaseWorker`(`core/device_worker.py`)。基类已封装:
|
||||
### 任务类型(TaskType)
|
||||
|
||||
- 设备获取(IP:5555 直连 / USB 远程 adb server,try/finally 保证释放)
|
||||
- adb 连接 + u2.connect(带 30 秒超时保护)
|
||||
- 状态上报(实时推送到前端监控大屏)
|
||||
- 异常捕获(设备离线不重试,其他异常按策略重试)
|
||||
- stop 停止信号(循环里检查 `self.stopped()`)
|
||||
- 心跳看门狗(120 秒无心跳自动标记卡死)
|
||||
| task_type | 名称 | 说明 |
|
||||
|-----------|------|------|
|
||||
| `generic_steps` | 通用步骤 | 步骤编辑器编排的流程(**当前唯一类型**) |
|
||||
|
||||
子类只需实现 `run_task(d)` 方法专注业务逻辑。
|
||||
新增专属任务类型的方法见 [doc/TASK_DEV.md](doc/TASK_DEV.md)。
|
||||
|
||||
### TaskType — 任务类型
|
||||
### 任务计划(TaskJob)
|
||||
|
||||
| 任务类型 | task_type | 说明 |
|
||||
|---------|-----------|------|
|
||||
| 通用步骤 | `generic_steps` | 可视化步骤编辑器编排流程,支持循环/点击/滑动/条件/OCR 等 |
|
||||
描述"什么任务、跑哪些设备、什么参数、何时跑、失败怎么重试":
|
||||
|
||||
### TaskJob — 任务计划
|
||||
|
||||
一个 TaskJob 描述"什么时候、在哪些设备上、用什么参数执行什么任务":
|
||||
|
||||
| 字段 | 说明 | 示例 |
|
||||
|------|------|------|
|
||||
| `task_type` | 任务类型 | `"generic_steps"` |
|
||||
| `target` | 目标设备 | `{"mode": "all"}` 或 `{"mode": "group", "group_name": "A组"}` 或 `{"mode": "serial", "serial": "192.168.1.100:5555"}` |
|
||||
| `params` | 任务参数(与默认值深合并) | `{"max_duration": 0, "steps": [{"type": "open_app", "params": {"package": "com.ss.android.ugc.aweme"}}]}` |
|
||||
| `schedule` | 调度策略 | `{"mode": "once"}` 或 `{"mode": "cron", "cron": "0 9 * * *"}` 或 `{"mode": "cron_stop", "cron": "0 9 * * *", "stop_cron": "0 18 * * *"}` |
|
||||
| `retry` | 重试策略 | `{"max_attempts": 3, "delay": 60}` |
|
||||
| `enabled` | 是否启用 | `true` |
|
||||
|
||||
### 调度模式
|
||||
|
||||
| 模式 | 行为 |
|
||||
| 字段 | 说明 |
|
||||
|------|------|
|
||||
| `once` | 手动执行(前端点"立即执行") |
|
||||
| `cron` | 定时启动:到 cron 时间点自动启动所有目标设备 |
|
||||
| `cron_stop` | 定时启停:启动 cron 到点启动,停止 cron 到点停止本任务 worker |
|
||||
| `task_type` | 任务类型(不传默认 `generic_steps`) |
|
||||
| `target` | `{"mode":"all"}` / `{"mode":"group","group_name":"A组"}` / `{"mode":"serial","serial":"100.100.10.20:5555"}` |
|
||||
| `params` | 任务参数,与任务类默认值合并;含两个隐藏开关 `skip_offline`(默认 true)、`preempt`(默认 false) |
|
||||
| `schedule` | `{"mode":"once"}` / `{"mode":"cron","cron":"0 9 * * *"}` / `{"mode":"cron_stop","cron":...,"stop_cron":...}`,可选 `window` 运行窗口 |
|
||||
| `retry` | `{"max_attempts":1,"delay":60}` |
|
||||
| `enabled` | 是否参与调度 |
|
||||
|
||||
**简单设置**:编辑任务时选"定时启动/定时启动+停止"后,频率用下拉选择——每天(选时间)、每小时(整点)、每隔 N 小时、每周(选星期+时间)——cron 表达式自动生成,不需要懂 cron 语法。老手可在"自定义 cron(高级)"里直接填。
|
||||
**调度模式**:`once` 仅手动;`cron` 到点启动;`cron_stop` 到点启动 + 到点停止。cron 为标准 5 段 `分 时 日 月 周`,编辑器提供"每天/每小时/每隔 N 小时/每周"的可视化选择自动生成,也可手填。
|
||||
|
||||
cron 表达式为标准 5 段格式:`分 时 日 月 周`(如 `0 9 * * *` = 每天 9:00,`0 */2 * * *` = 每 2 小时整点,周 `0`/`7` 均为周日)
|
||||
**运行窗口**(`schedule.window`,如 `21:00-09:00`,支持跨午夜):窗口外定时触发与手动执行都不启动。
|
||||
|
||||
**运行窗口**:任务可勾选"启用运行窗口",设置每天允许运行的时间段(如 `21:00-09:00` = 晚 9 点到次日早 9 点,支持跨午夜)。窗口外**定时触发和手动执行都不会启动**(手动执行会提示"当前不在运行窗口内")。典型用法:`每小时`定时 + 窗口 `09:00-21:00`,即只在白天每小时跑一次。
|
||||
|
||||
### 设备分组
|
||||
|
||||
设备分组存于 SQLite,便于按批次/项目分组下发任务。一个 Job 指定 `target.mode="group"` 时,调度器展开为组内全部设备。
|
||||
**目标解析**(`TaskJob.resolve_serials`):`all` = 设备池 ∩ 在线(开了抢占则取全部在线池内设备);`group` = 分组 ∩ 设备池;`serial` = 指定设备。后两者默认跳过离线设备。
|
||||
|
||||
### 进度上报
|
||||
|
||||
Worker 通过 `self.set_progress()` 上报通用进度字段,前端统一解析展示:
|
||||
Worker 通过 `set_progress()` 上报统一字段,前端统一渲染:
|
||||
|
||||
```python
|
||||
self.set_progress(done=5, total=80, unit="视频",
|
||||
action_counts={"like": 3})
|
||||
self.set_progress(done=5, total=80, unit="视频", action_counts={"like": 3}, elapsed=120)
|
||||
```
|
||||
|
||||
前端展示:进度条 + `5/80 视频` + `点赞 3` 徽章。
|
||||
|
||||
---
|
||||
|
||||
## 配置说明
|
||||
|
||||
所有核心配置在 [config.py](file:///d:/platform-tools/config.py),**任务参数不放在这里**(放各自 `tasks/xxx.py` 顶部)。
|
||||
|
||||
| 配置项 | 默认值 | 说明 |
|
||||
|-------|--------|------|
|
||||
| `ADB_PATH` | 自动识别 | adb 二进制路径,自动区分 Windows/Linux |
|
||||
| `WEB_HOST` | `0.0.0.0` | Web 监听地址(0.0.0.0 支持局域网访问) |
|
||||
| `WEB_PORT` | `18050` | Web 端口(避开 Windows 动态端口范围) |
|
||||
| `DATA_DIR` | `data/` | 持久化数据目录 |
|
||||
| `APK_DIR` | `data/apks/` | APK 文件存储目录 |
|
||||
| `USB_ADB_HOST` | `100.100.10.1` | USB 设备所在部署机(220)的 Tailscale IP(USB 设备远程 adb server) |
|
||||
| `USB_ADB_PORT` | `5037` | 220 adb 容器监听端口(host 网络模式) |
|
||||
| `TAILSCALE_API_KEY` | (.env 配置) | Tailscale 管理 API key(Settings → API Access Tokens) |
|
||||
| `TAILSCALE_TAILNET` | 按邮箱前缀 | tailnet 名/ID |
|
||||
|
||||
**必须修改的配置**:`.env` 里的 `WEB_SECRET_KEY`(会话密钥,不入 git);其余均为可选(默认值开箱即用)。
|
||||
前端展示为进度条 + `5/80 视频` + 计数徽章 + 运行时长。
|
||||
|
||||
---
|
||||
|
||||
## Web 管理后台
|
||||
|
||||
### 页面结构
|
||||
单页应用(`templates/admin/monitor.html`),**7 个顶级 Tab**;「任务 / 工具 / 系统」内部还有页内子分栏(会记住上次选中位置)。
|
||||
|
||||
单页应用(`templates/admin/monitor.html`),6 个 Tab;任务/工具 Tab 内部再有页内子分栏:
|
||||
|
||||
| Tab | 功能 | 可见性 |
|
||||
| Tab | 内容 | 可见性 |
|
||||
|-----|------|--------|
|
||||
| 监控 | 设备状态大屏:在线/离线、型号、运行任务、当前动作、进度条、前台 App、截图、勾选批量操作(亮屏/息屏/停止);导航栏「📺 大屏」打开全屏监控墙(/wall,缩略图+统计+时钟,挂墙/电视用) | 所有登录用户(设备操作按钮需"设备控制"权限) |
|
||||
| 任务 | 子分栏:任务计划(CRUD/启用停用/立即执行/下次运行时间/**离线设备自动跳过**)、自定义动作(打包复用) | 所有登录用户可看,写操作需"任务管理"权限 |
|
||||
| 分组 | 设备分组管理:创建/编辑/删除分组 | 所有登录用户可看,写操作需"任务管理"权限 |
|
||||
| 日志 | 实时日志查看:按模块切换(core/task/web/action) | 需"日志查看"权限 |
|
||||
| 用户 | 用户管理:创建/删除/修改密码/分配权限 | 仅管理员 |
|
||||
| 工具 | 子分栏:剪贴板注入、adb 远程终端(快捷命令/自动 `-s`)、**设备池管理**(新增/停用/删除/一键重连/型号采集)、**远程看屏**(MJPEG 实时流 + 点击/滑动/按键/文字)、Tailscale 管理(改名/授权/密钥不过期/设置IP/auth key)、应用管理(APK 上传安装)、应用版本管理(按包名查所有设备版本)、设备已装应用 | 仅管理员 |
|
||||
| **监控** | 统计卡片 + 设备表(在线/型号/任务状态/进度/前台 App/最近错误,支持排序、搜索、分页、多选批量操作)+ 异常汇总 + **任务运行概况**(每张任务卡:执行任务 / 停用任务 + 覆盖设备彩色 chip);导航栏「📺 大屏」打开 `/wall` | 所有登录用户(设备操作按钮需"设备控制") |
|
||||
| **任务** | 子分栏:**任务计划**(CRUD / 启停 / 执行 / 下次运行时间 / 离线跳过 / 步骤编辑器)、**自定义动作**(步骤打包复用) | 可看;写操作需"任务管理" |
|
||||
| **日志** | 实时日志(按文件切换、可自动刷新) | 需"日志查看" |
|
||||
| **用户** | 用户 CRUD、改密、分配权限 | 仅管理员 |
|
||||
| **工具** | 8 个子分栏:剪贴板注入 / adb 远程终端 / Tailscale 管理 / 应用管理 / 应用版本管理 / 设备已装应用 / **设备池管理**(含自动发现)/ 设备分组 | 仅管理员 |
|
||||
| **AI 控制台** | 会话列表 + 对话区(Markdown 渲染、推理链折叠、token 统计)+ 实时画面(MJPEG)+ 目标设备选择;右上角:经验库 / 动作库 / 模型配置 | 仅管理员 |
|
||||
| **系统** | 子分栏:数据备份(导出 zip)/ 导入恢复(上传→校验预览→应用,重启生效) | 仅管理员 |
|
||||
|
||||
任务/工具 Tab 的子分栏会记住上次选中的位置;无权限的 tab 和按钮自动隐藏。
|
||||
### 权限模型
|
||||
|
||||
### 用户与权限
|
||||
默认账号 `admin/admin123`(管理员,权限不受限)。权限位:
|
||||
|
||||
默认账号 `admin` / `admin123`(管理员,拥有全部权限)。管理员可在"用户"Tab 创建普通用户并分配权限:
|
||||
| 权限位 | 键 | 覆盖 |
|
||||
|--------|----|------|
|
||||
| 任务管理 | `tasks` | 任务/分组/自定义动作的写操作 |
|
||||
| 设备控制 | `devices` | 停止设备、亮息屏、定位、清异常、前台扫描、元素抓取、步骤测试 |
|
||||
| 应用管理 | `apks` | APK 上传/安装/删除 |
|
||||
| 日志查看 | `logs` | 日志 Tab |
|
||||
|
||||
| 权限位 | 说明 | 覆盖功能 |
|
||||
|--------|------|---------|
|
||||
| 任务管理 `tasks` | 任务/自定义动作/分组的增删改、启停、立即执行 | 任务 Tab、分组 Tab 的写操作 |
|
||||
| 设备控制 `devices` | 停止设备、释放占用、清除异常、前台扫描、元素抓取 | 监控 Tab 的设备操作按钮、步骤编辑器的"抓取元素" |
|
||||
| 应用管理 `apks` | APK 上传、安装、删除 | 应用管理/设备已装应用(当前并入工具 Tab,工具页整体仅管理员可见) |
|
||||
| 日志查看 `logs` | 日志页 | 日志 Tab |
|
||||
|
||||
规则:
|
||||
- **管理员拥有全部权限**,不受权限位限制
|
||||
- 查看类接口(设备/任务/分组列表、状态、截图)所有登录用户可用
|
||||
- **用户管理仅管理员可用**;不能删除/取消最后一个管理员
|
||||
- 无权限的 tab 和按钮在界面上自动隐藏(后端同样拦截,返回 403)
|
||||
|
||||
### 前台 App 扫描
|
||||
|
||||
监控页"扫描前台App"按钮,获取所有设备当前前台 App。**不打扰设备**:
|
||||
|
||||
| 设备状态 | 处理方式 |
|
||||
|---------|---------|
|
||||
| worker 运行中(IP:5555) | 复用已有 ADB 连接查询 |
|
||||
| worker 运行中(USB) | 经 220 远程 adb server 查询 |
|
||||
| 完全空闲 | 返回"空闲"(不主动 connect,避免扰动共享 adb transport) |
|
||||
|
||||
### 截图功能
|
||||
|
||||
监控页每台设备可查看实时截图。用 `adb exec-out screencap -p`,只读操作,**任务运行中也能安全调用**(不抢占 u2 的 atx-agent 通道)。
|
||||
|
||||
### 元素抓取
|
||||
|
||||
任务编辑器的"抓取元素"按钮可拉取设备当前 UI 元素树,点击元素一键回填选择器。依赖本地运行的 uiautodev 服务(端口 20242),`web_server.py` 启动时会自动拉起。
|
||||
- 后端 `@perm_required` / `@admin_required` 拦截并返回 403;前端用 `data-perm` 属性与 `_can(perm)` 隐藏入口(**仅隐藏,安全依赖后端**)
|
||||
- 不能删除/降级最后一个管理员
|
||||
|
||||
---
|
||||
|
||||
## 任务系统
|
||||
## 任务与步骤
|
||||
|
||||
### 通用步骤(generic_steps)
|
||||
`generic_steps` 的执行内容全在 `params.steps`(JSON 数组),由步骤编辑器产出。**没有默认步骤**——空步骤任务执行时会明确报错。
|
||||
|
||||
通过可视化步骤编辑器编排任务流程,worker 按步骤顺序执行。支持的步骤类型:
|
||||
**18 种步骤**(完整参数见 [doc/TASK_DEV.md](doc/TASK_DEV.md)):
|
||||
|
||||
| 步骤类型 | 说明 |
|
||||
|---------|------|
|
||||
| `open_app` | 启动 App(指定包名,可选等待首页) |
|
||||
| `stop_app` | 强制结束 App(am force-stop,清后台,下次打开冷启动) |
|
||||
| `screen_on` | 亮屏(息屏时唤醒并滑动解锁) |
|
||||
| `screen_off` | 息屏 |
|
||||
| `keep_screen` | 保持亮屏/恢复自动息屏(充电时屏幕常亮,适合长任务) |
|
||||
| `key_event` | 按键:返回/Home/回车/菜单等(退出评论、返回上一页) |
|
||||
| `swipe` | 滑动(上/下/左/右,可配置时长) |
|
||||
| `swipe_until` | 滑动直到元素出现(最多 N 次,可选找到后点击) |
|
||||
| `click_xy` | 点击坐标(屏幕百分比,无选择器时兜底) |
|
||||
| `long_click` | 长按元素(选择器 + 时长) |
|
||||
| `wait_el` | 等待元素出现(条件等待,替代固定时长) |
|
||||
| `input_text` | 输入文字(随机候选/指定文字,可选输入前先清空) |
|
||||
| `click` | 点击元素(支持 xpath/description/resourceId/text 选择器) |
|
||||
| `wait` | 等待(可配置时长范围) |
|
||||
| `loop` | 循环块(含子步骤,可配置循环次数) |
|
||||
| `group` | 动作组(含子步骤,按序执行一次) |
|
||||
| `if_el` | 条件判断:找元素(支持 xpath 等选择器或 **OCR识别** 截屏匹配图片文字),命中执行"找到时"分支,未命中执行"未找到时"分支;OCR 命中可自动点击。分支可嵌套循环/条件判断 |
|
||||
| 类别 | 步骤 |
|
||||
|------|------|
|
||||
| 屏幕 | `screen_on` 亮屏 · `screen_off` 息屏 · `keep_screen` 保持亮屏 |
|
||||
| 应用与输入 | `open_app` 打开 App · `stop_app` 结束 App · `input_text` 输入文字 · `clipboard` 剪贴板注入 · `key_event` 按键 |
|
||||
| 交互 | `click` 点击元素 · `click_xy` 点击坐标 · `long_click` 长按 · `swipe` 滑动 · `swipe_until` 滑动直到元素出现 · `wait_el` 等待元素 · `wait` 等待时长 |
|
||||
| 流程 | `loop` 循环块 · `group` 动作组 · `if_el` 条件判断(元素或 **OCR 识别**) |
|
||||
|
||||
步骤编辑器特性:操作库按分类分组、卡片可拖拽排序/跨层级嵌套(循环套循环)、☑ 多选打包自定义动作、
|
||||
"测试此步骤"真机验证、"抓取元素"回填选择器、条件判断的 OCR 识别依赖 `rapidocr_onnxruntime`(跨平台)。
|
||||
要点:
|
||||
|
||||
### 新增 App 任务
|
||||
|
||||
参照 `tasks/generic/` 结构,即可新增一个专属任务类型,详见 [doc/TASK_DEV.md](doc/TASK_DEV.md)。
|
||||
(注:当前平台只保留 `generic_steps` 一种类型;绝大多数 App 操作直接用步骤编辑器编排即可,不必新建类型。)
|
||||
- 每一步都可有 `probability`(0-100,默认 100)决定本次是否执行
|
||||
- 容器类步骤(`loop`/`group`/`if_el`)可嵌套,**深度上限 5 层**
|
||||
- 选择器支持 `xpath` / `description` / `text` / `resourceId` / `descriptionContains` / `className`(`ocr` 仅条件判断)
|
||||
- **优先用文字/id 定位**,坐标 (`click_xy`) 是最脆的方式
|
||||
- 未知步骤类型、缺必填参数只告警跳过,不会中断任务链(排查时留意"看起来成功但没做事")
|
||||
|
||||
---
|
||||
|
||||
## 日志系统
|
||||
## AI 与 MCP
|
||||
|
||||
日志按模块分文件,自动滚动(10MB 一份,保留 5 份历史):
|
||||
### AI 控制台
|
||||
|
||||
| 文件 | 模块前缀 | 内容 |
|
||||
|------|---------|------|
|
||||
| `logs/core.log` | `core.*` | adb/worker/task_manager/设备池 核心程序 |
|
||||
在「AI 控制台」选一台设备,用自然语言下指令,AI 通过 MCP 工具看屏幕、点按、输入,边做边把过程流式显示出来。配置(模型 / API Key / 默认设备 / 最大步数)存在数据库 `app_meta`,不落 `.env`。
|
||||
|
||||
自带两个"自进化记忆":
|
||||
|
||||
- **经验库**:任务成功后把操作套路蒸馏成配方,下次相似任务自动召回注入;每日 03:47 由 AI 巡检建议清理(删除永远需人工确认)
|
||||
- **动作库**:把成功步骤沉淀为带元素定位的命名动作(禁坐标),可复用、可编辑
|
||||
|
||||
详细机制见 [doc/AI_CONSOLE.md](doc/AI_CONSOLE.md)。
|
||||
|
||||
### MCP(外部 AI 接入)
|
||||
|
||||
MCP Server 监听 `:8033`,暴露 19 个 `de_*` 工具(截屏、点击、滑动、输入、OCR、元素树、应用管理等)。写操作需 `MCP_ALLOW_WRITE=1`;设备正在跑任务时拒绝(`device_busy`);每次调用写审计日志。
|
||||
|
||||
```bash
|
||||
# 本机手动启动(生产容器由 scripts/start.sh 自动拉起)
|
||||
MCP_ALLOW_WRITE=1 MCP_PLATFORM_USER=admin MCP_PLATFORM_PASS=<密码> \
|
||||
python -m mcp_server.mcp_server
|
||||
```
|
||||
|
||||
工具清单与接入示例见 [doc/MCP.md](doc/MCP.md)。
|
||||
|
||||
---
|
||||
|
||||
## 配置说明
|
||||
|
||||
**密钥类配置统一放项目根 `.env`**(不入 git;模板见 [.env.example](.env.example))。加载规则:逐行解析后用 `os.environ.setdefault` 注入,**真实环境变量优先**。
|
||||
|
||||
| 配置 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `WEB_SECRET_KEY` | 未配置则随机 | 会话密钥;不配则每次重启登录态失效(**生产必须固定**) |
|
||||
| `WEB_HOST` / `WEB_PORT` | `0.0.0.0` / `18050` | Web 监听(**常量,改 config.py**) |
|
||||
| `ADB_PATH` | 自动识别 `bin/adb/` | adb 二进制(常量,按平台自动选) |
|
||||
| `DATA_DIR` / `APK_DIR` | `data/` / `data/apks/` | 持久化目录(常量) |
|
||||
| `USB_ADB_HOST` / `USB_ADB_PORT` | `100.100.10.1` / `5037` | USB 设备所在的部署机(远程 adb server) |
|
||||
| `DISCOVERY_PORT` / `DISCOVERY_INTERVAL` | `5555` / `60` | 设备自动发现(网段也在工具页配置,存 `app_meta`) |
|
||||
| `TAILSCALE_API_KEY` / `TAILSCALE_TAILNET` | 空 | Tailscale 管理功能 |
|
||||
| `WEB_SECRET_KEY` 之外的一切密钥 | — | 一律进 `.env`,**不要写进 config.py** |
|
||||
|
||||
> **任务参数不放 config.py**——放各自 `tasks/<name>/task.py` 顶部的 `DEFAULT_PARAMS`。
|
||||
|
||||
完整键表(含 `MCP_*` / `AGENT_*`)见 [doc/DEVELOPMENT.md](doc/DEVELOPMENT.md) §配置速查。
|
||||
|
||||
---
|
||||
|
||||
## 日志
|
||||
|
||||
按模块分文件,单文件 10MB 滚动、保留 5 份:
|
||||
|
||||
| 文件 | 前缀 | 内容 |
|
||||
|------|------|------|
|
||||
| `logs/core.log` | `core.*` | adb / device_worker / task_manager / 设备池 |
|
||||
| `logs/task.log` | `task.*` | 任务执行(worker 业务逻辑) |
|
||||
| `logs/web.log` | `web.*` | Web 请求/管理 |
|
||||
| `logs/action.log` | `action.*` | 操作执行(点赞/评论等) |
|
||||
|
||||
使用方式:
|
||||
| `logs/web.log` | `web.*` | Web 请求与管理操作 |
|
||||
| `logs/action.log` | `action.*` | 操作执行 |
|
||||
|
||||
```python
|
||||
from core.logger import get_logger
|
||||
log = get_logger("task.generic") # 写入 task.log
|
||||
log.info(f"[{self.serial}] 开始任务")
|
||||
log = get_logger("task.generic") # → logs/task.log
|
||||
```
|
||||
|
||||
Web 后台"日志"Tab 可实时查看各模块日志。
|
||||
|
||||
---
|
||||
|
||||
## 常用脚本
|
||||
|
||||
| 脚本 | 用途 |
|
||||
|------|------|
|
||||
| `python web_server.py` | 启动 Web 管理后台 |
|
||||
| `python scripts/pack.py` | 打包项目为 zip(排除日志/数据库/APK) |
|
||||
| `bash scripts/supervise.sh` | 进程守护(web_server 崩溃自动重启) |
|
||||
「日志」Tab 可在线查看。
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 端口被占用(WinError 10013/10048)
|
||||
|
||||
`web_server.py` 会自动重试候选端口(原端口 → 127.0.0.1:原端口 → 127.0.0.1:原端口+1~+5)。如果全部失败,检查 Windows 动态端口范围:
|
||||
|
||||
```bash
|
||||
netsh interface ipv4 show excludedportrange protocol=tcp
|
||||
```
|
||||
|
||||
修改 `config.py` 中的 `WEB_PORT` 到一个不在排除范围内的端口。
|
||||
|
||||
### 设备显示离线
|
||||
|
||||
先确认本机 `adb devices` 能看到设备(工具 → 设备池管理 → 一键重连);看不到则检查 Tailscale 是否在线、设备是否加入了正确的 tailnet(平台与设备必须在同一 tailnet)。
|
||||
|
||||
### 新增设备后任务不调度它
|
||||
|
||||
新设备需在「工具 → 设备池管理」添加(serial 为 `IP:5555`),仅连上 adb 不会进入设备池。添加后自动连接并采集型号,下一轮任务即可调度。
|
||||
|
||||
### u2.connect 卡死
|
||||
|
||||
`u2.connect()` 在 atx-agent 无响应时会永久 hang。基类已用 `ThreadPoolExecutor + 30 秒超时` 保护,超时自动放弃。如果频繁超时,检查设备 atx-agent 是否正常(重启设备或重新推送 atx-agent)。
|
||||
|
||||
### 任务运行中看门狗误杀
|
||||
|
||||
看门狗 120 秒无心跳会标记卡死。长耗时操作(如长视频等待)需在循环内周期性调用 `self.heartbeat()`。
|
||||
|
||||
### 中文输入失败
|
||||
|
||||
uiautomator2 默认 IME 不支持中文,需切到 FastInput 输入法:
|
||||
|
||||
```python
|
||||
try:
|
||||
d.set_fastinput_ime(True)
|
||||
d.send_keys("中文内容")
|
||||
finally:
|
||||
d.set_fastinput_ime(False)
|
||||
```
|
||||
|
||||
### 修改 core/ 后不生效
|
||||
|
||||
`web_server.py` 以 `debug=False` 运行,Python 不会热重载。修改 `core/` 目录下的文件后**必须重启 web_server 进程**。
|
||||
|
||||
### 元素抓取按钮不可用
|
||||
|
||||
依赖 uiautodev 服务(端口 20242)。确保已安装 `pip install uiautodev`。`web_server.py` 启动时会自动拉起该服务。
|
||||
| 现象 | 处理 |
|
||||
|------|------|
|
||||
| 端口被占用(WinError 10013/10048) | 启动会自动回退候选端口(`18050` → `127.0.0.1:18050` → `127.0.0.1:18051..18055`);仍失败则改 `WEB_PORT`(注意 Windows 动态端口排除段) |
|
||||
| 设备显示离线 | 「工具 → 设备池管理」一键重连;确认设备在线且同一网络(生产走 Tailscale 同 tailnet) |
|
||||
| 新加的设备不被调度 | 必须**加入设备池**(仅 adb 连上不算);确认该设备为"启用"状态 |
|
||||
| `u2.connect` 卡死 | 基类有 30s 超时保护;频繁超时说明 atx-agent 异常,重启设备或重新推送 |
|
||||
| 任务运行中被看门狗标记卡死 | 看门狗 120s 无心跳即判定;长循环内需周期性 `self.heartbeat()` |
|
||||
| 任务"成功"但什么都没做 | 步骤类型未知/缺必填参数会被**告警跳过**;查 `logs/task.log` 的 WARNING |
|
||||
| 中文输入失败 | u2 默认 IME 不支持中文,需 `set_fastinput_ime(True)`(`input_text` 步骤已处理) |
|
||||
| 改了 `core/` 不生效 | 服务以 `debug=False` 运行、不热重载;**必须重启**。前端改动还需强刷浏览器(Ctrl+Shift+R) |
|
||||
| 元素抓取按钮不可用 | 依赖本机 uiautodev(:20242),`web_server.py` 启动时自动拉起;未安装时 `pip install uiautodev` |
|
||||
|
||||
---
|
||||
|
||||
## 更多文档
|
||||
## 文档索引
|
||||
|
||||
**完整文档入口 → [doc/README.md](doc/README.md)**(文档地图、阅读路径、维护约定)
|
||||
|
||||
| 文档 | 内容 |
|
||||
|------|------|
|
||||
| [doc/DEVELOPMENT.md](doc/DEVELOPMENT.md) | **开发手册**:开发流程、git 工作流、技术红线、环境、本地开发 |
|
||||
| [doc/TASK_DEV.md](doc/TASK_DEV.md) | 任务开发指南(新增 App 任务的完整模板和规范) |
|
||||
| [doc/ARCHITECTURE.md](doc/ARCHITECTURE.md) | 架构详解(分层设计、数据流、关键设计决策) |
|
||||
| [doc/DEPLOY.md](doc/DEPLOY.md) | 部署指南(环境准备、设备池配置、生产部署) |
|
||||
| [doc/STF_REMOVAL.md](doc/STF_REMOVAL.md) | STF 摘除迁移记录(阶段 0-3 已完成,含多实例锁方案) |
|
||||
| [doc/API.md](doc/API.md) | API 接口文档(全部 HTTP 接口说明) |
|
||||
| [doc/ARCHITECTURE.md](doc/ARCHITECTURE.md) | 架构详解(分层、装配顺序、线程模型、设备生命周期、调度链路、设计决策) |
|
||||
| [doc/DATA_MODEL.md](doc/DATA_MODEL.md) | 数据模型(表结构、迁移、`app_meta`、数据目录、备份覆盖清单) |
|
||||
| [doc/API.md](doc/API.md) | HTTP 接口全量说明 |
|
||||
| [doc/TASK_DEV.md](doc/TASK_DEV.md) | 任务与步骤开发(18 种步骤、选择器、自定义动作、新增任务类型) |
|
||||
| [doc/MCP.md](doc/MCP.md) · [doc/MCP_DESIGN.md](doc/MCP_DESIGN.md) | MCP 使用手册 / 设计文档 |
|
||||
| [doc/AI_CONSOLE.md](doc/AI_CONSOLE.md) · [doc/AI_TASK_GEN.md](doc/AI_TASK_GEN.md) | AI 控制台机制 / AI 建任务设计(规划) |
|
||||
| [doc/DEPLOY.md](doc/DEPLOY.md) | 部署与运维(含生产容器、备份导入、故障排查) |
|
||||
| [doc/DEVELOPMENT.md](doc/DEVELOPMENT.md) | 开发手册(git 流程、技术红线、本地开发、文档同步约定) |
|
||||
| [doc/STF_REMOVAL.md](doc/STF_REMOVAL.md) | 摘除 OpenSTF 的历史记录 |
|
||||
|
||||
> **注意**:所有 git 操作(含 push 到 dev)都需负责人确认后才能执行,详见开发手册。修改 `core/`、`tasks/`、`templates/` 后需重启服务/强刷浏览器才生效。
|
||||
> ⚠️ **改动必须同步文档**:功能/配置/接口/表结构的任何增删改,都要在同一个 commit 里更新对应文档(红线,详见 [doc/README.md](doc/README.md) §3)。
|
||||
> ⚠️ **git 操作需负责人确认**(含 push 到 dev),详见 [doc/DEVELOPMENT.md](doc/DEVELOPMENT.md)。
|
||||
|
||||
---
|
||||
|
||||
@@ -440,10 +398,10 @@ finally:
|
||||
|
||||
| 组件 | 用途 |
|
||||
|------|------|
|
||||
| Flask + Flask-Login | Web 后台 + 用户认证 |
|
||||
| Flask-SQLAlchemy | SQLite 数据持久化 |
|
||||
| APScheduler | 定时任务调度 |
|
||||
| uiautomator2 | Android UI 自动化 |
|
||||
| uiautodev | UI 元素抓取(步骤编辑器"抓取元素") |
|
||||
| Flask + Flask-Login + Flask-SQLAlchemy | Web 后台 / 认证 / SQLite ORM |
|
||||
| APScheduler | 定时任务调度(任务 + 经验巡检两个独立调度器) |
|
||||
| uiautomator2 / uiautodev | Android UI 自动化 / 元素抓取 |
|
||||
| rapidocr_onnxruntime (+ opencv-headless) | 屏幕 OCR |
|
||||
| pyaxmlparser | APK 元信息解析 |
|
||||
| 自建设备池 | 设备清单/在线状态/型号(SQLite + adb) |
|
||||
| fastmcp | MCP Server(Streamable HTTP)+ AI 控制台 Agent |
|
||||
| adb(项目自带 `bin/adb/`) | 设备连接与底层操作 |
|
||||
|
||||
Reference in New Issue
Block a user