83 lines
3.2 KiB
TypeScript
83 lines
3.2 KiB
TypeScript
/**
|
|
* 继电器高层动作 helper —— 用语义名驱动物理按键,所有参数可配/可传,不写死。
|
|
*
|
|
* 典型用法(添加流程前置):
|
|
* await enterPairingMode('remote'); // 按 config 默认(凸+凹 3s)
|
|
* await enterPairingMode('meter', { holdMs: 2500 }); // 临时覆盖时长
|
|
* await pressButton('remote', 'convex', 800); // 单键点按
|
|
*
|
|
* 端口/波特率默认走 env(SERIAL_PORT/SERIAL_BAUD),也可经 opts 传入。
|
|
* 默认每次自建并关闭控制器(一次性动作);要在一个会话里连续操作,传 opts.controller 复用。
|
|
*/
|
|
import { SerialController, SerialOptions } from './serial_controller';
|
|
import { resolveRelayAction, resolveRelayButton } from '../../config/relay.config';
|
|
|
|
export interface RelayActionOptions extends SerialOptions {
|
|
/** 覆盖配置里的按住时长(毫秒)。 */
|
|
holdMs?: number;
|
|
/** 复用已打开的控制器(不则自建并在结束时关闭)。 */
|
|
controller?: SerialController;
|
|
}
|
|
|
|
/** 用一个已开/自建的控制器执行 fn,自建的用完即关。 */
|
|
async function withController<T>(
|
|
opts: RelayActionOptions,
|
|
fn: (c: SerialController) => Promise<T>
|
|
): Promise<T> {
|
|
if (opts.controller) return fn(opts.controller);
|
|
const c = new SerialController(opts);
|
|
await c.open();
|
|
try {
|
|
return await fn(c);
|
|
} finally {
|
|
await c.close();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 触发设备的命名动作(默认 'pairing' 进配对):按 config 解析通道列表+时长,
|
|
* 多通道则同帧"同时按下",按住后整体释放。返回实际触发的通道与时长。
|
|
*/
|
|
export async function triggerRelayAction(
|
|
device: string,
|
|
action = 'pairing',
|
|
opts: RelayActionOptions = {}
|
|
): Promise<{ channels: number[]; holdMs: number; desc?: string }> {
|
|
const resolved = resolveRelayAction(device, action);
|
|
const holdMs = opts.holdMs ?? resolved.holdMs;
|
|
await withController(opts, (c) => c.pulseChannels(resolved.channels, holdMs));
|
|
console.log(`relay: ${device}.${action} → 通道[${resolved.channels.join(',')}] 按住 ${holdMs}ms${resolved.desc ? ' (' + resolved.desc + ')' : ''}`);
|
|
return { ...resolved, holdMs };
|
|
}
|
|
|
|
/** 让设备进入添加/配对模式(= triggerRelayAction(device,'pairing'))。 */
|
|
export function enterPairingMode(device: string, opts: RelayActionOptions = {}) {
|
|
return triggerRelayAction(device, 'pairing', opts);
|
|
}
|
|
|
|
/** 点按设备某个命名按键 ms 毫秒(单键)。 */
|
|
export async function pressButton(
|
|
device: string,
|
|
button: string,
|
|
ms = 500,
|
|
opts: RelayActionOptions = {}
|
|
): Promise<number> {
|
|
const ch = resolveRelayButton(device, button);
|
|
await withController(opts, (c) => c.pulse(ch, ms));
|
|
console.log(`relay: 点按 ${device}.${button} → 通道 ${ch} ${ms}ms`);
|
|
return ch;
|
|
}
|
|
|
|
/** 同时按住一组命名按键 ms 毫秒后释放(任意组合)。 */
|
|
export async function pressButtonsTogether(
|
|
device: string,
|
|
buttons: string[],
|
|
ms = 500,
|
|
opts: RelayActionOptions = {}
|
|
): Promise<number[]> {
|
|
const channels = buttons.map((b) => resolveRelayButton(device, b));
|
|
await withController(opts, (c) => c.pulseChannels(channels, ms));
|
|
console.log(`relay: 同时按 ${device}.[${buttons.join('+')}] → 通道[${channels.join(',')}] ${ms}ms`);
|
|
return channels;
|
|
}
|