Events and Subscriptions
The SDK provides an event-driven architecture that allows you to subscribe to real-time updates about your nodes and devices. This includes local network discovery events and node update notifications.
The userInstance used in this documentation refers to ESPRMUser class instance obtained in User Sign in step.
Overview
The event subscription system enables:
- Real-time local discovery: Automatically detect when nodes become available on the local network
- Transport management: Update node transport configurations dynamically
- Node updates: Receive notifications about node state changes
- Flexible callbacks: Register custom handlers for different event types
Event Types
The SDK supports the following event types through the ESPRMEventType enum:
| Event Type | Description |
|---|---|
localDiscovery | Triggered when nodes are discovered on the local network. Used to update node transport configurations. |
nodeUpdates | Triggered when node state changes occur (parameter updates, connectivity changes, etc.). |
Local Discovery and Transport Updates
How It Works
The local discovery mechanism follows this flow:
Step 1: Register Local Discovery Callback
To receive local discovery events, register a callback using the subscribe method:
import { ESPRMEventType } from "@espressif/rainmaker-base-sdk";
// Define your callback to handle discovered nodes
const localDiscoveryCallback = (discoveredNodeData) => {
console.log("Node discovered locally:", discoveredNodeData);
// discoveredNodeData contains:
// - nodeId: The ID of the discovered node
// - transportDetails: Transport configuration including baseUrl
const { nodeId, transportDetails } = discoveredNodeData;
// Update your node store with the new transport information
// This allows the node to communicate over local network
updateNodeTransport(nodeId, transportDetails);
};
// Subscribe to local discovery events
try {
userInstance.subscribe(ESPRMEventType.localDiscovery, localDiscoveryCallback);
console.log("Subscribed to local discovery events");
} catch (error) {
console.error("Error subscribing to local discovery:", error);
}
Your callback should have access to your node store (or equivalent state management system) so that when a node is discovered locally, you can update the node's availableTransports field with the local transport details. The availableTransports is a Record<ESPTransportMode, ESPTransportConfig> where each transport mode maps to its configuration.
Step 2: SDK Starts Discovery
When you call the subscribe method with ESPRMEventType.localDiscovery:
- SDK registers the callback: Your callback is stored in the internal
eventCallbacksregistry - Discovery manager is created: An instance of
ESPDiscoveryManageris created with the local protocol - Discovery starts: The manager calls
startDiscovery()which uses theESPDiscoveryAdapterto scan the local network - Callbacks are triggered: When nodes are discovered, your callback is invoked with the node details
// This happens automatically inside the SDK when you subscribe
// You don't need to call these directly - just subscribe!
// Internal SDK flow (for reference):
// 1. eventCallbacks[ESPRMEventType.localDiscovery].push(callback)
// 2. new ESPDiscoveryManager(ESPDiscoveryProtocol.local)
// 3. localDiscoveryManager.startDiscovery(discoveryCallback)
Local discovery requires the ESPDiscoveryAdapter to be configured during SDK initialization. Learn more about adapters.
Step 3: Update Node Transport
When your callback receives discovery events, update the node's available transports:
// Example: Update node transport in your state management
const localDiscoveryCallback = (discoveredNodeData) => {
const { nodeId, transportDetails } = discoveredNodeData;
// transportDetails structure:
// {
// type: "local",
// metadata: {
// baseUrl: "http://192.168.1.100" // Local IP of the node
// }
// }
// Find the node in your store
const node = findNodeById(nodeId);
if (node) {
// Initialize availableTransports as a Record if it doesn't exist
node.availableTransports = node.availableTransports || {};
// Add or update the local transport configuration
// availableTransports is a Record<ESPTransportMode, ESPTransportConfig>
node.availableTransports[transportDetails.type] = transportDetails;
console.log(
`Node ${nodeId} is now available locally at ${transportDetails.metadata.baseUrl}`
);
}
};
Transport Priority
Setting Transport Order
The setTransportOrder method defines the priority of transports the SDK should use when communicating with nodes (e.g., setting device parameters).
import { ESPRMBase, ESPTransportMode } from "@espressif/rainmaker-base-sdk";
// Define transport priority: try local first, fallback to cloud
const transportOrder = [
ESPTransportMode.local, // First priority
ESPTransportMode.cloud, // Fallback
];
try {
ESPRMBase.setTransportOrder(transportOrder);
console.log("Transport order set successfully");
} catch (error) {
console.error("Error setting transport order:", error);
}
- Local First: Set
[ESPTransportMode.local, ESPTransportMode.cloud]for faster response times when on the same network - Cloud First: Set
[ESPTransportMode.cloud, ESPTransportMode.local]for consistent behavior regardless of network location
How Transport Order Works with Discovery
- Discovery updates availableTransports: When local discovery finds a node, it adds local transport to the node's
availableTransportsrecord using the transport mode as the key - SDK checks transport order: When you set a device parameter, the SDK checks the transport order you've defined
- SDK attempts communication: The SDK tries each transport in order based on what's available in the
availableTransportsrecord - Fallback mechanism: If the first transport fails, the SDK automatically falls back to the next available transport
// Example workflow:
// 1. Set transport order to prefer local
ESPRMBase.setTransportOrder([ESPTransportMode.local, ESPTransportMode.cloud]);
// 2. Subscribe to local discovery to populate availableTransports
userInstance.subscribe(ESPRMEventType.localDiscovery, (data) => {
updateNodeTransport(data.nodeId, data.transportDetails);
});
// 3. When you set a parameter, SDK automatically uses local transport if available
await device.setParamValue("power", true);
// SDK checks: node.availableTransports[ESPTransportMode.local] exists? Use it!
// If local fails or unavailable, SDK falls back to cloud
Node Update Events
Subscribe to node update events to receive real-time notifications about node state changes:
const nodeUpdateCallback = (updateData) => {
console.log("Node update received:", updateData);
// updateData contains information about:
// - Which node was updated
// - What parameters changed
// - New parameter values
// Update your UI or state accordingly
handleNodeUpdate(updateData);
};
try {
userInstance.subscribe(ESPRMEventType.nodeUpdates, nodeUpdateCallback);
console.log("Subscribed to node updates");
} catch (error) {
console.error("Error subscribing to node updates:", error);
}
Node update events require the ESPNotificationAdapter to be configured for push notifications. Learn more about push notifications.
Managing Subscriptions
Subscribe to Events
Subscribe a single or multiple callbacks to an event:
// Subscribe single callback
userInstance.subscribe(ESPRMEventType.localDiscovery, callback1);
// Subscribe multiple callbacks at once
userInstance.subscribe(ESPRMEventType.localDiscovery, [callback1, callback2]);
Unsubscribe from Events
Remove a specific callback from an event:
userInstance.unsubscribe(ESPRMEventType.localDiscovery, callback1);
Remove All Callbacks
Remove all callbacks for a specific event or all events:
// Remove all callbacks for a specific event
userInstance.removeAllCallbacks(ESPRMEventType.localDiscovery);
// Remove all callbacks for all events
userInstance.removeAllCallbacks();
Complete Example
Here's a complete example showing how to set up event subscriptions for a typical application:
import {
ESPRMBase,
ESPRMEventType,
ESPTransportMode,
} from "@espressif/rainmaker-base-sdk";
// Step 1: Set transport order (prefer local for speed)
ESPRMBase.setTransportOrder([ESPTransportMode.local, ESPTransportMode.cloud]);
// Step 2: Define local discovery callback
const handleLocalDiscovery = (discoveredNodeData) => {
const { nodeId, transportDetails } = discoveredNodeData;
console.log(`Node ${nodeId} discovered on local network`);
console.log(`Base URL: ${transportDetails.metadata.baseUrl}`);
// Update your state/store with the new transport
updateNodeAvailableTransports(nodeId, transportDetails);
};
// Step 3: Define node update callback
const handleNodeUpdates = (updateData) => {
console.log("Node state changed:", updateData);
// Update your UI with the latest node data
refreshNodeData(updateData);
};
// Step 4: Subscribe to events
try {
// Subscribe to local discovery
userInstance.subscribe(ESPRMEventType.localDiscovery, handleLocalDiscovery);
// Subscribe to node updates
userInstance.subscribe(ESPRMEventType.nodeUpdates, handleNodeUpdates);
console.log("All event subscriptions active");
} catch (error) {
console.error("Error setting up subscriptions:", error);
}
// Step 5: Cleanup when done (e.g., on app unmount)
const cleanup = () => {
userInstance.removeAllCallbacks(ESPRMEventType.localDiscovery);
userInstance.removeAllCallbacks(ESPRMEventType.nodeUpdates);
};
Best Practices
- Keep callbacks lightweight: Callbacks should update state/store quickly without blocking the event loop
- Handle errors gracefully: Always wrap state updates in try-catch blocks
- Clean up subscriptions: Remove callbacks when components unmount or when they're no longer needed
- Use appropriate transport order: Choose transport priority based on your use case (local vs cloud first)
- Update availableTransports properly: Ensure your callback has access to node store to update transport configurations. Remember that
availableTransportsis aRecord<ESPTransportMode, ESPTransportConfig>, not an array - Test both scenarios: Test your app when nodes are on local network and when they're only accessible via cloud
Related Documentation
- Set Transport Order - Configure transport priority
- Device Control - Control devices using different transports
- Push Notifications - Set up push notifications for node updates
- Adapters - Configure required adapters