/** * @license * Copyright 2025-2026 Open Home Foundation * SPDX-License-Identifier: Apache-2.0 */ import type { BorderRouterEntry, MatterNode } from "@matter-server/ws-client"; import type { CategorizedDevices, NetworkType, SignalLevel, ThreadConnection, ThreadEdgePair, ThreadExternalDevice, ThreadNeighbor, ThreadRoute } from "./network-types.js"; /** * WiFi Diagnostics info from cluster 0x36/54. */ export interface WiFiDiagnostics { /** BSSID as hex string */ bssid: string | null; /** RSSI in dBm (-120 to 0) */ rssi: number | null; /** WiFi channel */ channel: number | null; /** Security type */ securityType: number | null; /** WiFi version */ wifiVersion: number | null; } /** * Detects the network type from the NetworkCommissioning cluster feature map. * Uses attribute 0/49/65532 (FeatureMap). */ export declare function getNetworkType(node: MatterNode): NetworkType; /** * Thread protocol version supported by the device's Thread interface. * Uses NetworkCommissioning cluster (0x31/49) ThreadVersion attribute (0x0A/10). */ export declare function getThreadVersion(node: MatterNode): number | undefined; /** * Human-readable Thread version string from the Version TLV value. * Unmapped TLVs render as `Thread unknown (N)` so the raw value stays * visible for diagnostics. */ export declare function formatThreadVersion(tlv: number): string; /** * Categorizes nodes by their network type. * Node IDs are stored as strings to avoid BigInt precision loss. */ export declare function categorizeDevices(nodes: Record): CategorizedDevices; /** * Gets the Thread routing role for a node. * Uses attribute 0/53/1 (RoutingRole, nullable per Matter spec). */ export declare function getThreadRole(node: MatterNode): number | undefined; /** * Gets the Thread channel for a node. * Uses attribute 0/53/0 (Channel, nullable per Matter spec). */ export declare function getThreadChannel(node: MatterNode): number | undefined; /** * Gets the Thread extended PAN ID for a node. * Uses attribute 0/53/4 (ExtendedPanId, nullable per Matter spec). * * The WebSocket JSON reviver only revives integers above Number.MAX_SAFE_INTEGER * as bigint; smaller uint64 values arrive as plain number, so accept both. */ export declare function getThreadExtendedPanId(node: MatterNode): bigint | undefined; /** * Gets the Thread extended address (EUI-64) for a node. * * Uses General Diagnostics cluster (0x0033/51) NetworkInterfaces attribute (0/51/0). * The NetworkInterface struct has: * - Field 4: HardwareAddress (base64 encoded EUI-64) * - Field 7: Type (4 = Thread) * * Returns as BigInt. Only upper 48 bits should be used for matching due to JSON precision loss. */ export declare function getThreadExtendedAddress(node: MatterNode): bigint | undefined; /** * Gets the Thread extended address as a hex string for display. * Uses General Diagnostics NetworkInterfaces (0/51/0). */ export declare function getThreadExtendedAddressHex(node: MatterNode): string | undefined; /** * Counts entries in the Thread neighbor table without normalizing each entry. * Use this in hot paths where only the cardinality matters; the full parse * does a base64 decode per entry that adds up across re-renders. */ export declare function getNeighborTableLength(node: MatterNode): number; /** * Parses the Thread neighbor table from a node's attributes. * Attribute 0/53/7 (NeighborTable) is an array of neighbor objects. * The data uses numeric keys matching the Matter spec field IDs. */ export declare function parseNeighborTable(node: MatterNode): ThreadNeighbor[]; /** * Parses the Thread route table from a node's attributes. * Attribute 0/53/8 (RouteTable) is an array of route objects. * The data uses numeric keys matching the Matter spec field IDs. */ export declare function parseRouteTable(node: MatterNode): ThreadRoute[]; /** * Find a route table entry for a specific destination by extended address. * Returns the route entry if found, undefined otherwise. */ export declare function findRouteByExtAddress(node: MatterNode, targetExtAddr: bigint): ThreadRoute | undefined; /** * Count the number of routable destinations for a node (from route table). * Only counts entries where allocated=true and linkEstablished=true. * This is typically only meaningful for router nodes. */ export declare function getRoutableDestinationsCount(node: MatterNode): number; /** * Calculate combined bidirectional LQI from route table entry. * Returns average of lqiIn and lqiOut if both are non-zero. */ export declare function getRouteBidirectionalLqi(route: ThreadRoute): number | undefined; /** * Gets the RLOC16 (short address) for a Thread node. * Uses attribute 0/53/64 (Rloc16, 0x0040). */ export declare function getThreadRloc16(node: MatterNode): number | undefined; /** * Builds a map of extended addresses (BigInt) to node IDs for Thread devices. * Uses General Diagnostics NetworkInterfaces (0/51/0) for the hardware address. * Node IDs are stored as strings to avoid BigInt precision loss. */ export declare function buildExtAddrMap(nodes: Record): Map; /** * Builds a map of RLOC16 (short addresses) to node IDs for Thread devices. * Used as fallback when ExtAddress is not available. * Node IDs are stored as strings to avoid BigInt precision loss. */ export declare function buildRloc16Map(nodes: Record): Map; /** * Finds external Thread devices - addresses seen in neighbor tables that don't match * any commissioned device. Classifies each against the optional Border Router registry: * matched ones are emitted as kind:"br" with full mDNS enrichment; the rest stay as * kind:"unknown". Uses RLOC16 as fallback when extended address matching fails. */ export declare function findUnknownDevices(nodes: Record, extAddrMap: Map, rloc16Map: Map, borderRouters?: ReadonlyMap): ThreadExternalDevice[]; /** * Decoded form of the MeshCoP `_meshcop` TXT `sb` (state bitmap) field. Layout per * OpenThread's `border_agent_txt_data.hpp` (`openthread/openthread`, the de-facto reference * implementation for Thread Border Router service publication): * * bits 0-2 Connection Mode (0=Disabled, 1=PSKc/DTLS, 2=PSKd/DTLS, 3=Vendor, 4=X.509) * bits 3-4 Thread Interface State (0=NotInit, 1=Init/inactive, 2=Init/active) * bits 5-6 Availability (0=Infrequent, 1=High) * bit 7 BBR Active (0/1) * bit 8 BBR Is Primary (0=secondary, 1=primary; only meaningful when BBR Active) * bits 9-10 Thread Role (0=Detached, 1=Child, 2=Router, 3=Leader) * bit 11 ePSKc Supported (0/1) * bits 12-13 Multi-AIL State (0=Disabled, 1=Not detected, 2=Detected) * bits 14-31 Reserved */ export interface DecodedStateBitmap { connectionMode?: string; connectionModeValue: number; threadInterfaceStatus?: string; threadInterfaceStatusValue: number; availability?: string; availabilityValue: number; bbr: boolean; /** "primary" / "secondary" — only meaningful when {@link bbr} is true. */ bbrFunction?: string; threadRole?: string; threadRoleValue: number; epskcSupported: boolean; multiAilState?: string; multiAilStateValue: number; /** Hex of any bits beyond bit 13 (reserved/future). Undefined when zero. */ reservedHex?: string; } /** * Decodes a MeshCoP state bitmap hex string (e.g. "000005B1") per the OpenThread reference * layout. Returns undefined if the input is not a valid hex value. */ export declare function decodeMeshcopStateBitmap(hex: string | undefined): DecodedStateBitmap | undefined; /** Determine signal level from a Thread neighbor's LQI. */ export declare function getSignalLevel(neighbor: ThreadNeighbor): SignalLevel; /** * Map an LQI value (0-3 in practice on OpenThread) to a signal level. * 0 = "none" (no recent valid frames — stale/dead link). */ export declare function getSignalLevelFromLqi(lqi: number): SignalLevel; /** Map a signal level to its theme-aware color. */ export declare function signalLevelToColor(level: SignalLevel): string; /** Gets the signal color for a Thread neighbor based on its LQI. */ export declare function getSignalColor(neighbor: ThreadNeighbor): string; /** * Get signal color from an LQI value (0-3 in practice on OpenThread). * 0 = grey (no link), 1 = red, 2 = orange, 3 = green. */ export declare function getSignalColorFromLqi(lqi: number): string; /** Strips trailing dot and `.local` suffix from an mDNS hostname. */ export declare function stripMdnsHostname(hostname: string): string; export { getDeviceName } from "../../util/node-name.js"; /** * Gets the human-readable name for a Thread routing role. */ export declare function getThreadRoleName(role: number | undefined): string; /** * Parses WiFi diagnostics from a node's attributes. * Cluster 0x36/54 - WiFi Network Diagnostics. */ export declare function getWiFiDiagnostics(node: MatterNode): WiFiDiagnostics; /** * Gets the signal color for a given RSSI value. */ export declare function getSignalColorFromRssi(rssi: number | null): string; /** * Gets WiFi security type name. */ export declare function getWiFiSecurityTypeName(securityType: number | null): string; /** * Gets WiFi version name. */ export declare function getWiFiVersionName(version: number | null): string; /** * Represents a connection from the perspective of a specific node. * Includes both neighbors this node reports AND nodes that report this node as their neighbor. */ export interface NodeConnection { /** The connected node ID (number for known nodes, string for unknown devices) */ connectedNodeId: number | string; /** The connected MatterNode if it's a known device */ connectedNode?: MatterNode; /** Extended address hex string for display */ extAddressHex: string; /** Signal strength info (if available) */ signalColor: string; signalLevel: SignalLevel; lqi: number | null; rssi: number | null; /** Whether this connection is from THIS node's neighbor table (true) or from the OTHER node's table (false) */ isOutgoing: boolean; /** True when only the peer reports this edge — this node has no matching neighbor-table entry. Surfaces true asymmetric visibility, distinct from a reverse view caused by filtering. */ isReverseOnly: boolean; /** Whether this is an unknown/external device */ isUnknown: boolean; /** Path cost from route table (1 = direct, higher = multi-hop). Only available for routers. */ pathCost?: number; /** Bidirectional LQI from route table (average of lqiIn and lqiOut) */ bidirectionalLqi?: number; } /** * Creates a canonical pair key from two node IDs. * The key is always ordered so that the same pair produces the same key regardless of direction. */ export declare function makePairKey(a: string, b: string): string; /** * Computes a numeric signal score for edge comparison. * Lower score = weaker signal (worst case). */ export declare function getEdgeSignalScore(conn: ThreadConnection): number; /** * Builds edge pairs for all Thread connections. * Each pair represents two connected nodes with up to 2 directional edges * (one from each node's neighbor/route table). No dedup is performed — * callers are responsible for selecting which edge to display per pair. */ export declare function buildThreadEdgePairs(nodes: Record, extAddrMap: Map, rloc16Map: Map, unknownDevices: ThreadExternalDevice[]): Map; /** * Filter options for edge visibility, matching the graph's filter pipeline. */ export interface EdgeFilterOptions { hideOfflineNodes?: boolean; hideWeakSignalEdges?: boolean; hideMediumSignalEdges?: boolean; hideStrongSignalEdges?: boolean; } /** * Derives NodeConnection[] from pre-computed edge pairs for a given node. * Uses the same edge pairs as the graph, ensuring the side panel and the * graph always agree on which connections exist. * * The function mirrors the graph's exact pipeline: * 1. Filter each edge independently (offline cascade + signal level) * 2. Among survivors per pair, prefer the outgoing edge (matches graph * highlight swap); fall back to worst signal (matches graph dedup) * * When filters are omitted, no filtering is applied and the outgoing * edge is preferred (useful for the "update connections" dialog). * * One entry per connected peer (no duplicates). */ export declare function getNodeConnectionsFromPairs(nodeId: string, edgePairs: Map, nodes: Record, filters?: EdgeFilterOptions): NodeConnection[]; //# sourceMappingURL=network-utils.d.ts.map