src.nth.io/

summaryrefslogtreecommitdiff
path: root/src/device.ts
diff options
context:
space:
mode:
Diffstat (limited to 'src/device.ts')
-rw-r--r--src/device.ts72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/device.ts b/src/device.ts
new file mode 100644
index 0000000..1c0d0ea
--- /dev/null
+++ b/src/device.ts
@@ -0,0 +1,72 @@
+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<PairedNode> {
+ 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<void> {
+ let timer: NodeJS.Timeout | undefined;
+ const timeout = new Promise<never>((_, 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);
+ }
+}