AI_UIAutomation/utils/common/curtain.helper.ts

119 lines
5.8 KiB
TypeScript

/**
* Curtain / Curtain 3 连接后专属流程(选模式 + 行程校验)。
* **curtain 与 curtain3 校准流程不同**,分开实现:
* - curtain3:已实测全程跑通(Custom Calibration:朝向→已关闭→跳磁铁→Move left/right)。
* - curtain(base):校准流程与 curtain3 不同,待该设备可连接后补全;当前先走"稍后校准"。
*
* 作为 addDeviceWithSerialPairing 的 postConnectSteps 传入。所有点击用文字/desc 定位,不写死坐标。
*/
import { DeviceDriver } from '../../drivers/types';
import { sleep, waitForSource } from './element.helper';
export interface CurtainAddOptions {
/** true=做行程校验(需设备装在真实导轨上、电机能跑);false=Install and calibrate later 跳过校验。 */
calibrate?: boolean;
/** Determine 位置每个方向的行进等待(ms),默认 15000。 */
moveWaitMs?: number;
}
async function tapText(driver: DeviceDriver, txt: string): Promise<boolean> {
const el = driver.platform === 'android'
? await driver.findElementRaw('-android uiautomator', `new UiSelector().text("${txt}")`)
: await driver.findElementRaw('name', txt);
if (el) { await driver.tapElement(el); return true; }
return false;
}
async function tapDesc(driver: DeviceDriver, desc: string): Promise<boolean> {
const el = driver.platform === 'android'
? await driver.findElementRaw('-android uiautomator', `new UiSelector().descriptionContains("${desc}")`)
: await driver.findElementRaw('predicate string', `label CONTAINS "${desc}" OR name CONTAINS "${desc}"`);
if (el) { await driver.tapElement(el); return true; }
return false;
}
/** 连接后第一步(curtain/curtain3 共用):Select Mode 选"单边开合" → Confirm。 */
async function selectModeOpenOneSide(driver: DeviceDriver): Promise<void> {
await waitForSource(driver, 'Select Mode', 60000).catch(() => {});
if (!(await tapDesc(driver, 'Open from one side'))) await tapText(driver, 'Open from one side');
await sleep(1000);
await tapText(driver, 'Confirm');
}
/** Curtain 3 连接后流程(含已验证的 Custom Calibration)。 */
export async function curtain3PostConnect(driver: DeviceDriver, opts: CurtainAddOptions = {}): Promise<void> {
const calibrate = opts.calibrate ?? false;
const moveWait = opts.moveWaitMs ?? 15000;
await selectModeOpenOneSide(driver);
await waitForSource(driver, 'Install', 30000).catch(() => {});
if (!calibrate) {
await tapText(driver, 'Install and calibrate later');
console.log('curtain3: 走 Install and calibrate later(跳过行程校验)');
return;
}
await tapText(driver, 'Install');
// Curtain Track 选轨道 → 底部 Skip
await waitForSource(driver, 'rail type', 15000).catch(() => {});
await tapText(driver, 'Skip');
// Calibrate → Custom Calibration
await waitForSource(driver, 'Custom Calibration', 15000).catch(() => {});
await tapText(driver, 'Custom Calibration');
// ① Confirm Orientation:勾选"logo 朝内"单选行 → Next
// 注意:用唯一子串 "logo is facing inwards"(单选行 "SwitchBot logo is facing inwards"),
// 不能用 "facing inwards" —— 会误匹配描述段 "...logo on your device is facing inwards",导致单选没勾上、Next 灰着。
await waitForSource(driver, 'Confirm Orientation', 15000).catch(() => {});
if (!(await tapDesc(driver, 'logo is facing inwards'))) await tapDesc(driver, 'facing inwards');
await sleep(800);
await tapText(driver, 'Next');
// ② Adjust Position:勾选"已关闭窗帘"单选行 → Start Calibration(同样用唯一子串避免误匹配描述)
await waitForSource(driver, 'fully closed', 15000).catch(() => {});
if (!(await tapDesc(driver, 'fully closed my curtains'))) await tapDesc(driver, 'fully closed');
await sleep(800);
await tapText(driver, 'Start Calibration');
// ③ Magnet Detection:Skip magnet detection → 弹框 Skip
await waitForSource(driver, 'Magnet Detection', 15000).catch(() => {});
await tapText(driver, 'Skip magnet detection');
await sleep(1500);
await tapText(driver, 'Skip');
// ④ Determine Fully open:Move left 行进 → 点"暂停"停在位 → Auto-Calibrate Close。
// Move left 点击后按钮会变成 "Pause"(窗帘行进中),必须先点 Pause 停下,否则位置没记录 → "Not calibrated"。
await waitForSource(driver, 'Move left', 20000).catch(() => {});
await tapText(driver, 'Move left');
await sleep(moveWait); // 让窗帘行进到目标全开位
// 行进中按钮变 Pause:点它停下(中英/可能为 "Pause"/"暂停")
if (!(await tapText(driver, 'Pause'))) await tapText(driver, '暂停');
await sleep(1500);
await tapText(driver, 'Auto-Calibrate Close');
await sleep(5000); // 等自动关闭校准结算(期间可能出现 "Something went wrong",仍可 Finish)
// ⑤ Finish:点一次可能不离开校验页(页面结算中),重试直到离开 Custom Calibration 页
for (let i = 0; i < 6; i++) {
const src = await driver.getSource();
if (!/Custom Calibration|Move left|Auto-Calibrate/i.test(src)) break; // 已离开校验页 = 完成
await tapText(driver, 'Finish');
await sleep(3000);
}
console.log('curtain3: Custom Calibration 完成');
}
/**
* Base Curtain 连接后流程 —— 校准流程与 curtain3 **不同**:行程是 Move left → 等待 → Move right → 等待。
* 该设备目前连接不上,校准流程待可连接后实测补全;当前默认走"稍后校准"。
*/
export async function curtainPostConnect(driver: DeviceDriver, opts: CurtainAddOptions = {}): Promise<void> {
await selectModeOpenOneSide(driver);
await waitForSource(driver, 'Install', 30000).catch(() => {});
await tapText(driver, 'Install and calibrate later');
if (opts.calibrate) {
console.log('curtain(base): 行程校验流程(Move left→Move right)待该设备可连接后实测补全;当前已走"稍后校准"');
}
}