跳到主要内容

Node Store

NodeStore is the device graph manager. It stores and tracks all devices (nodes), their parameters, services, connectivity status, and local transports.

What it does

When you fetch a user's devices or receive a device update (via push), the store makes that data observable so your UI re-renders automatically when anything changes.

Core responsibilities:

  • Store devicesnodesList and nodesByIDMap for fast lookup
  • Track real-time changes — Parameters, connectivity, OTA status
  • Sync with SDK — Keep _raw node objects aligned with observable state
  • Manage local transports — Track WiFi, BLE, Thread discovery

API reference

Properties

PropertyTypePurpose
nodesListESPCDFNode[]All nodes (computed from nodesByIdMap)
nodesByIdMapRecord<string, ESPCDFNode>Observable map for fast O(1) lookups

Getting the store

import { initCDF } from "@espressif/rainmaker-base-cdf";

const espCDF = await initCDF({ sdkAdaptorRegistry });
const { nodeStore } = espCDF;

Transport discovery

Local transports (BLE, WiFi, Thread) are registered via subscriptionStore.transport.listen(), not through NodeStore. See Subscription Store for details.

How to use it

Query nodes

// All nodes
const nodes = espCDF.nodeStore.nodesList;

// Single node by ID
const node = espCDF.nodeStore.getNodeById("node-id");

Control device parameters

Set one parameter:

const param = node.devices?.[0]?.params?.find((p) => p.name === "Power");
await param?.setValue(true);

Set multiple parameters at once:

const node = espCDF.nodeStore.getNodeById("node-id")!;
await node.setMultipleParams({
Light: { Power: true, Brightness: 80 },
Fan: { Speed: 3 },
});

Devices contain parameters. Services contain params too. Both can be read-only or controllable.

const node = espCDF.nodeStore.getNodeById("node-id")!;

// Iterate devices and their params
for (const device of node.devices ?? []) {
console.log("Device:", device.name, device.type);
for (const param of device.params ?? []) {
console.log(" Param:", param.name, "=", param.value);
}
}

// Iterate services
for (const service of node.services ?? []) {
console.log("Service:", service.name, service.type);
for (const param of service.params ?? []) {
console.log(" Param:", param.name);
}
}

Check connectivity

Connectivity updates arrive via the real-time push path. Read the observable field:

const node = espCDF.nodeStore.getNodeById("node-id")!;
const isConnected = node.connectivityStatus?.connected;

// Available transports (local WiFi/BLE/Thread discovery)
const transports = node.availableTransports;

Update device metadata

await node.updateMetadata({ 
location: "Living Room",
timezone: "Asia/Kolkata"
});

// Or set timezone separately
await node.setTimeZone("Asia/Kolkata");

Manage OTA updates

Check and push firmware updates:

const { data: otaInfo } = (await node.checkOTAUpdate?.()) ?? {};
if (otaInfo?.available) {
await node.pushOTAUpdate({ firmwareImageId: otaInfo.imageId });
}

// Check update status by job ID
const status = await node.getOTAUpdateStatus(otaJobId);

Remove a node

await node.delete();
// NodeStoreSynchronizer removes it automatically

Reactive UI components

Wrap components that read nodes with observer(). MobX re-renders only when the fields you read actually change.

Example: Watch node list size

// Re-renders when nodesList changes (nodes added/removed)
const NodeCount = observer(function NodeCount({ espCDF }: { espCDF: ESPCDF }) {
return <Text>{espCDF.nodeStore.nodesList.length} devices</Text>;
});

Example: Control a single parameter

import { observer } from "mobx-react-lite";
import type { ESPCDF } from "@espressif/rainmaker-base-cdf";

// Re-renders ONLY when this param's value changes
// Other params on the node changing won't trigger a re-render
const LightSwitch = observer(function LightSwitch({
espCDF,
nodeId,
}: {
espCDF: ESPCDF;
nodeId: string;
}) {
const node = espCDF.nodeStore.getNodeById(nodeId);
const powerParam = node?.devices?.find(d => d.type === "esp.device.lightbulb")
?.params?.find(p => p.name === "Power");

if (!powerParam) return null;

return (
<Switch
value={powerParam.value as boolean}
onValueChange={(val) => powerParam.setValue(val)}
/>
);
});

Best practice: Keep observer components small and granular. A component that reads only param.value re-renders only when that value changes, avoiding unnecessary renders.

See also

Real-time updates

Implementation

API Reference

On this page