Files
auto_control/doc/DEPLOY.md
T
butubb fd829a6063 docs: doc/ 全量同步 dev 现状——API 目录补全(AI 控制台/系统备份/自动发现等)、去 STF 过时口径、补 generic_steps 与配置键速查;确立「功能/配置改动须同步文档」红线
- doc/API.md:补方法/路径标题,权限分层修正,新增 AI 控制台(/api/agent/*)、系统备份(/api/system/backup/*)、设备自动发现(/api/devices/discovery/*)、tap_text/summary/health/devices-apps 等整节端点,去 STF 残留
- doc/TASK_DEV.md:STF 时代描述清理;新增 §2.10 generic_steps(18 节点与必填/嵌套/静默跳过语义)、§2.11 自定义动作与单步测试、/api/jobs 盲存校验语义、resolve_serials/抢占语义、模板构造函数签名修正
- doc/DEPLOY.md:数据备份改为推荐「系统→数据备份」功能并说明重启生效目录,端口表 STF7100→MCP8033,补 start.sh 生产链路与 MCP_PLATFORM_PASS 同步,故障排查去 STF
- doc/MCP.md:加「现状边界」(平台级任务 CRUD 未 MCP 化,规划见 AI_TASK_GEN §9),busy/平台会话说明,MCP_ALLOWED_SERIALS 语义纠正
- doc/MCP_DESIGN.md:加实现现状对照、错误码、独立容器改演进备选、里程碑状态、API 映射表按实现重写
- doc/ARCHITECTURE.md:Tab/子分栏/线程模型/数据表/蓝图表去 STF,补 device_discovery/agent/system_backup/经验巡检等
- doc/DEVELOPMENT.md:新增 §5.6「改动必须同步文档」红线、§2.3 配置键速查、蓝图化新增 API 流程、文档索引补登记
- doc/STF_REMOVAL.md:加历史记录状态横幅
- doc/AI_TASK_GEN.md:新增 AI 建任务设计稿(含 §9 需转 MCP 工具分层)
2026-09-09 16:05:56 +08:00

14 KiB
Raw Blame History

部署指南

本文介绍如何从零部署 platform-tools 设备自动化后台。


1. 环境准备

1.1 Python 环境

  • Python 3.10+(推荐 3.12)
  • 安装后确认 python --version 和 pip 可用
# 验证
python --version    # 应输出 3.10+
pip --version

1.2 设备池(已摘除 OpenSTF 依赖)

设备池由平台自身管理(SQLite devices 表 + 本机 adb 在线状态),不再依赖 OpenSTF。 新增设备在管理后台「工具 → 设备池管理」添加(serial 形如 100.100.10.x:5555)。

USB 设备(serial 无冒号)插在部署机(220)时,经 220 的 adb server 驱动:

  • 220 的 adb 容器需为 host 网络模式(5037 已监听所有网卡,含 Tailscale)
  • 平台配置 USB_ADB_HOST(默认 100.100.10.1)/ USB_ADB_PORT(默认 5037)

1.3 adb 工具

项目自带 adb 二进制在 bin/adb/ 目录:

  • Windows:bin/adb/adb.exe + 依赖 dll(已包含)
  • Linux:bin/adb/adb(需 chmod +x)
  • macOS:bin/adb/adb(需 chmod +x)

如需替换为自己的 adb 版本,把对应平台的 adb 放进 bin/adb/ 即可,config.py 会自动识别操作系统。

1.4 设备准备

设备需满足:

  • 开启 USB 调试(设置 → 开发者选项)
  • 转网络调试:USB 连上后 adb -s <serial> tcpip 5555(管理后台「adb 终端」有一键快捷命令)
  • 设备加入 Tailscale(同一账号,获得 100.100.10.x IP)
  • 在「工具 → 设备池管理」添加 IP:5555(自动尝试连接,任务运行时 u2 自动推送 atx-agent)

2. 安装部署

2.1 获取代码

# 方式一:直接拷贝项目目录
# 方式二:解压打包文件(python scripts/pack.py 生成的 zip)

2.2 安装依赖

cd platform-tools
pip install -r requirements.txt

依赖清单(requirements.txt):

包 版本 用途
Flask >=2.3,<4.0 Web 框架
Flask-Login >=0.6 用户认证
Flask-SQLAlchemy >=3.0,<4.0 SQLite ORM
APScheduler >=3.10,<4.0 定时调度
requests >=2.28 HTTP 客户端
uiautomator2 >=3.0 Android UI 自动化
uiautodev >=0.14 UI 元素抓取
pyaxmlparser >=0.3.27 APK 元信息解析
rapidocr_onnxruntime >=1.4 屏幕 OCR(条件判断的 OCR识别 选择器,中英文模型随包内置,跨平台)
fastmcp >=2.0 MCP Server 与 AI 控制台 Agent(Streamable HTTP 服务端/客户端)
paramiko >=3.0 SSH 运维预留(历史 STF SSH 通道退役;配置 STF_SSH_PASSWORD 时走密码认证,未配置则退回系统 ssh 免密)

服务器(无显示器/Linux)环境建议把 opencv-python 换成 opencv-python-headless(rapidocr 依赖 cv2,两者取一)。

uiautomator2 首次连接设备时会自动推送 atx-agent 到设备,无需手动安装。

2.3 修改配置

密钥类配置统一放项目根目录 .env(已被 .gitignore 排除,不会提交到 git; config.py 不再内置任何密钥):

# .env 示例
WEB_SECRET_KEY=随机字符串(会话密钥,python -c "import secrets;print(secrets.token_hex(32))" 生成)
TAILSCALE_API_KEY=你的Tailscale_API_key
# USB_ADB_HOST=100.100.10.1   # 220 的 Tailscale IP(USB 设备远程 adb server,默认值已可用)

其他配置按需调整:

配置项 默认值 何时修改
WEB_HOST 0.0.0.0 仅本机访问改为 127.0.0.1
WEB_PORT 18050 端口冲突时修改
ADB_PATH 自动识别 用自定义 adb 时修改
USB_ADB_HOST 100.100.10.1 USB 设备所在部署机(220)的 Tailscale IP
USB_ADB_PORT 5037 220 adb 容器监听端口(host 网络模式)
TAILSCALE_TAILNET 按邮箱前缀 tailnet 名称/ID(个人账号一般为登录邮箱前缀)
DISCOVERY_PORT 5555 设备自动发现扫描的 adb 端口(网段默认局域网 + Tailscale,可在设备池面板改)
DISCOVERY_INTERVAL 60 自动发现扫描间隔(秒)

配置来源区分:WEB_HOST/WEB_PORT/ADB_PATH 是 config.py 常量(直接改文件,不经 .env); TAILSCALE_API_KEY/TAILSCALE_TAILNET/USB_ADB_HOST/USB_ADB_PORT/DISCOVERY_PORT/DISCOVERY_INTERVAL 由 config.py 以环境变量读取,可在 .env 覆盖; BACKUP_DIR/RESTORE_STAGING_DIR/RESTORE_PENDING_DIR 是常量(硬编码到 data/,见 §3.5)。

未配置 WEB_SECRET_KEY:启动时随机生成(每次重启登录态失效,生产务必配置固定值)。 工具页 Tailscale 管理前置:.env 写入 TAILSCALE_API_KEY 后重启服务; 未配置时管理分区显示明确提示,不影响其他功能。 (历史遗留的 STF_URL/STF_TOKEN/STF_SSH_* 等配置:config.py 仍读取但无任何功能使用,仅历史保留;生产 .env 可留空。)

2.4 启动服务

命令行启动

python web_server.py

(推荐配合 scripts/supervise.sh 进程守护,见 3.1 节)

生产容器(220)入口 scripts/start.sh(docker-compose 的 python-app 服务 command):

  1. 依赖就绪守卫:flask/u2/uiautodev/rapidocr/cv2/fastmcp 全可用则跳过安装;否则 pip install -r requirements.txt 并做 cv2 环境修复(卸 GUI opencv → 装 headless)
  2. 后台拉起 MCP server:MCP_ENABLED 默认 1 时执行 python3 -m mcp_server.mcp_server(MCP_ALLOW_WRITE=1、MCP_PLATFORM_USER 默认 admin、MCP_PLATFORM_PASS 兜底 admin123),日志 /tmp/mcp_server.log
  3. 前台启动主服务:exec python -u web_server.py

注意:

  • scripts/supervise.sh 只守护 web_server,不拉起 MCP——容器场景 MCP 由 start.sh 拉起,不要用 supervise.sh 替代容器入口
  • AI 控制台依赖 MCP:AGENT_MCP_URL 默认 http://127.0.0.1:8033/mcp(mcp_agent/config.py)
  • 手动起 web_server 需另启 MCP:MCP_ALLOW_WRITE=1 python -m mcp_server.mcp_server
  • 改过 admin 密码务必同步 MCP_PLATFORM_PASS(start.sh 兜底 admin123 会登录失败)
  • 发布链路:dev 开发测试完成 → 负责人确认合并 main → 220 git pull → 重启 python-app 容器生效(详见 DEVELOPMENT §6)

2.5 验证部署

  1. 控制台看到 启动服务: http://localhost:18050/ 即成功
  2. 浏览器访问 http://localhost:18050/
  3. 用 admin/admin123 登录
  4. 监控页应显示设备池中的设备(本机 adb 在线 + SQLite 配置清单,serial 形如 100.100.10.x:5555)

3. 生产部署建议

3.1 进程守护

用进程守护工具确保服务自动重启:

Windows(NSSM):

nssm install platform-tools "C:\Python312\python.exe" "D:\platform-tools\web_server.py"
nssm start platform-tools

Linux(systemd):

# /etc/systemd/system/platform-tools.service
[Unit]
Description=Platform Tools Web Server
After=network.target

[Service]
Type=simple
User=www
WorkingDirectory=/opt/platform-tools
ExecStart=/usr/bin/python3 web_server.py
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target

通用脚本(Linux/macOS,无需 systemd):

项目自带 scripts/supervise.sh:web_server 崩溃自动重启、带退避和重启上限(防崩溃死循环)。

# 用 venv 的 python 守护
PYTHON=./.venv/bin/python bash scripts/supervise.sh

进程守护只保证服务重启,不恢复已运行的任务(worker 状态在内存)。

崩溃后占用自愈(需人工核实):历史 AUTO_RELEASE_STALE_OCCUPY 机制已随 STF 摘除失效(全库代码不再读取该配置)。设备池的占用互斥仍在(任务 running/connecting 的设备会被锁),但崩溃后残留占用如何释放、是否自动清理,需按当前实现核实后补写本节。

Docker(生产 python-app 容器):

docker-compose 已配置 restart: unless-stopped,web_server 进程退出 → 容器退出 → Docker 自动重启。建议再加健康检查,让编排感知服务存活:

# docker-compose.yaml 的 python-app 服务下添加
healthcheck:
  test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:18050/api/health', timeout=3)"]
  interval: 30s
  timeout: 5s
  retries: 3
  start_period: 10s

3.2 反向代理(可选)

如需 HTTPS 或 80 端口,用 Nginx 反向代理:

server {
    listen 80;
    server_name auto.example.com;

    location / {
        proxy_pass http://127.0.0.1:18050;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

3.3 安全加固

  • 修改默认密码:登录后立即在"用户"Tab 修改 admin 密码
  • 最小权限分配:需要多人使用后台时,在"用户"Tab 创建普通用户并只勾选必要权限 (任务管理/设备控制/应用管理/日志查看),不要把 admin 密码共享出去
  • 会话密钥 SECRET_KEY:在 .env 写固定 WEB_SECRET_KEY(python -c "import secrets;print(secrets.token_hex(32))" 生成);未配置时启动随机生成(每次重启登录态失效,生产务必配置固定值)
  • 限制访问:生产环境把 WEB_HOST 改为 127.0.0.1,配合反向代理
  • 防火墙:只开放必要端口

3.4 日志管理

  • 日志自动滚动(10MB 一份,保留 5 份)
  • 日志目录 logs/,可在"日志"Tab 在线查看
  • 长期运行建议定期清理或配置 logrotate

3.5 数据备份

优先推荐平台功能「系统 → 数据备份导出/导入」(仅 admin):

  • 导出:POST /api/system/backup/export → 用 sqlite 在线备份 API 对 data/users.db 做一致快照,打包 zip(users.db + manifest.json + 可选 apks/*.apk)
  • 导入:上传 zip/.db → 校验预览(完整性/必需表/schema 版本告警)→ 确认后自动把当前库快照到 data/backups/pre_restore_*.db(安全网可回滚)→ 落 data/restore_pending/ → 重启 web_server 生效(web_server 在 init_db 前自动消费恢复任务)

目录与常量:

目录 用途
data/backups/ 导出临时 zip + 恢复前快照 pre_restore_*.db + 校验失败的 restore_failed_*
data/restore_staging/ 导入暂存,TTL 30 分钟未应用自动清理
data/restore_pending/ 待生效恢复任务(重启时消费)

常量 BACKUP_DIR / RESTORE_STAGING_DIR / RESTORE_PENDING_DIR(config.py L63-68,非 .env,已 .gitignore)。

手工备份 data/ 目录仍可作兜底,但整库恢复建议走上述功能(在线一致快照 + 预恢复备份 + 重启原子生效,避免手工替换被 WAL/占用文件破坏)。


4. 网络配置

4.1 端口说明

端口 服务 说明
18050 Web 后台 主服务端口(config.py 可改)
20242 uiautodev 元素抓取服务(自动启动,固定端口)
8033 MCP MCP 手机控制 Server(scripts/start.sh 自动拉起,MCP_ENABLED=0 可关)
5555 adb 设备 adb 网络端口(设备端)

4.2 Windows 端口问题(仅 Windows)

Windows 可能将某些端口范围划为动态排除范围,导致绑定失败(WinError 10013)。

# 查看排除的端口范围
netsh interface ipv4 show excludedportrange protocol=tcp

如果 18050 在排除范围内,修改 config.py 的 WEB_PORT 到一个不在排除范围内的端口。

4.3 局域网访问

  • WEB_HOST = "0.0.0.0" 允许局域网访问
  • 需要添加防火墙入站规则(Windows 手动添加,或参考 netsh advfirewall firewall add rule)
  • 局域网其他机器访问 http://部署机IP:18050/

5. 更新升级

5.1 代码更新

# 1. 停止服务
# 2. 替换代码文件(或解压新的 zip)
# 3. 重新安装依赖(如有新增)
pip install -r requirements.txt
# 4. 启动服务
python web_server.py

5.2 数据库迁移

  • SQLite 表结构变化时,init_db() 会自动 db.create_all() 创建新表
  • 旧 groups.json / jobs.json 首次启动自动迁移到 SQLite
  • 迁移后 JSON 文件归档为 .migrated(保留备份,不再迁移)

5.3 注意事项

  • 修改 core/ 目录下的文件后必须重启 web_server(debug=False 不热重载)
  • 修改 templates/ 下的 HTML 文件:Flask 模板默认不缓存,但建议重启确保生效
  • 修改 tasks/ 下的文件后必须重启(任务注册在启动时完成)

6. 故障排查

6.1 启动失败

现象 原因 解决
ModuleNotFoundError: No module named 'flask' 依赖未安装 pip install -r requirements.txt
WinError 10013 端口被排除/权限不足 改端口或用管理员运行
WinError 10048 端口被占用 改端口或杀占用进程
监控页设备列表为空 设备不在池中 / adb 连不上 「工具 → 设备池管理」确认已添加且在线,检查设备网络与 5555 端口

6.2 设备连接失败

现象 原因 解决
DeviceOfflineError u2 连接超时 / atx-agent 无响应 检查设备网络,重启设备或重新推送 atx-agent
u2.connect 超时 atx-agent 无响应 重启设备/重新推送 atx-agent
adb connect failed 设备网络不通/端口未开放 检查设备 IP 和 5555 端口
设备显示离线 状态缓存/误报 管理后台设备池「重连」,或「扫描前台 App」复测

6.3 任务不执行

现象 原因 解决
任务列表有任务但不执行 任务未启用 / cron 未到点 检查 enabled 和 schedule
立即执行无反应 无可用设备 检查设备池是否有空闲设备
worker 状态 error 查看日志的 last_error 查看 logs/core.log 和 logs/task.log
看门狗误杀 长操作未心跳 在长循环内加 self.heartbeat()

6.4 日志查看

# 查看核心日志
# 方式一:Web 后台"日志"Tab
# 方式二:直接看文件
# logs/core.log   — adb/worker/task_manager
# logs/task.log   — 任务执行
# logs/web.log    — Web 请求
# logs/action.log — 操作执行