import { NodeId } from "@matter/main"; import type { CommissioningController } from "@project-chip/matter.js"; import { NodeStates, type PairedNode } from "@project-chip/matter.js/device"; import { Log } from "./logging.js"; const log = new Log("device"); export function nodeStateName(state: NodeStates): string { switch (state) { case NodeStates.Connected: return "connected"; case NodeStates.Disconnected: return "disconnected"; case NodeStates.Reconnecting: return "reconnecting"; case NodeStates.WaitingForDeviceDiscovery: return "waiting for device discovery"; } } /** * Connects to the commissioned node using operational discovery (DNS-SD by * node identity, never a stored IP address) and waits until the node is fully * initialized from the device. * * The returned PairedNode keeps reconnecting in the background; observe * `events.stateChanged` for connectivity transitions. */ export async function connectDevice( controller: CommissioningController, nodeId: bigint, timeoutMs = 60_000, ): Promise { const node = await controller.getNode(NodeId(nodeId)); node.events.stateChanged.on(state => { log.debug(`Node ${nodeId} state: ${nodeStateName(state)}`); }); if (!node.initialized) { log.info(`Connecting to Matter node ${nodeId}...`); node.connect(); await waitForInitialization(node, nodeId, timeoutMs); } else if (!node.isConnected) { node.connect(); await waitForInitialization(node, nodeId, timeoutMs); } log.info(`Connected to Matter node ${nodeId}`); return node; } async function waitForInitialization(node: PairedNode, nodeId: bigint, timeoutMs: number): Promise { let timer: NodeJS.Timeout | undefined; const timeout = new Promise((_, reject) => { timer = setTimeout( () => reject( new Error( `Timed out after ${Math.round(timeoutMs / 1000)}s waiting for node ${nodeId}. ` + `The device may be offline or unreachable over IPv6.`, ), ), timeoutMs, ); }); try { await Promise.race([node.events.initializedFromRemote, timeout]); } finally { clearTimeout(timer); } }