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