/** * 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 { 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 { 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 { 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 { 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 { 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)待该设备可连接后实测补全;当前已走"稍后校准"'); } }