跳到主要内容

事件与订阅

该 SDK 提供了一套事件驱动架构,支持订阅节点与设备的实时状态更新。具体包括本地网络发现事件和节点更新通知。

注意事项

本文档中使用的 userInstance 指代在用户登录步骤中获取的 ESPRMUser 类实例。

概览

事件订阅系统支持以下功能:

  • 实时本地发现:自动检测节点何时在本地网络上变为可用。
  • 传输管理:动态更新节点传输配置。
  • 节点更新:接收节点状态变更通知。
  • 灵活回调:为不同事件类型注册自定义处理器。

事件类型

通过 ESPRMEventType 枚举,SDK 支持以下事件类型:

事件类型描述
localDiscovery在本地网络发现节点时触发,用于更新节点传输配置。
nodeUpdates节点状态变更(参数更新、连接变化等)时触发。

本地发现与传输更新

工作原理

本地发现机制遵循以下流程:

步骤 1:注册本地发现回调

若要接收本地发现事件,可使用 subscribe 方法注册回调:

import { ESPRMEventType } from "@espressif/rainmaker-base-sdk";

// 定义用于处理已发现节点的回调
const localDiscoveryCallback = (discoveredNodeData) => {
console.log("Node discovered locally:", discoveredNodeData);

// discoveredNodeData 包含:
// - nodeId:已发现节点的 ID
// - transportDetails:包含 baseUrl 的传输配置

const { nodeId, transportDetails } = discoveredNodeData;

// 将新的传输信息写入节点存储
// 这样可通过本地网络与节点通信
updateNodeTransport(nodeId, transportDetails);
};

// 订阅本地发现事件
try {
userInstance.subscribe(ESPRMEventType.localDiscovery, localDiscoveryCallback);
console.log("Subscribed to local discovery events");
} catch (error) {
console.error("Error subscribing to local discovery:", error);
}
重要信息:节点存储访问

回调应能访问节点存储(或等效的状态管理系统),这样当在本地发现节点时,可以用本地传输详情更新该节点的 availableTransports 字段。availableTransports 的类型是 Record<ESPTransportMode, ESPTransportConfig>,每个传输模式映射到其配置。

步骤 2:SDK 启动发现

当以 ESPRMEventType.localDiscovery 调用 subscribe 方法时:

  1. SDK 注册回调:回调会存入内部的 eventCallbacks 注册表。
  2. 创建发现管理器:以本地协议创建 ESPDiscoveryManager 实例。
  3. 开始发现:管理器调用 startDiscovery(),使用 ESPDiscoveryAdapter 扫描本地网络。
  4. 触发回调:发现节点后,以节点详情调用回调。
// 订阅本地发现事件时上述操作会在 SDK 内部自动发生
// 无需手动调用这些方法,只需订阅即可

// SDK 内部流程(供参考):
// 1. eventCallbacks[ESPRMEventType.localDiscovery].push(callback)
// 2. new ESPDiscoveryManager(ESPDiscoveryProtocol.local)
// 3. localDiscoveryManager.startDiscovery(discoveryCallback)
需要发现适配器

要启用本地发现功能,必须在 SDK 初始化期间配置 ESPDiscoveryAdapter。更多信息请查看适配器文档

步骤 3:更新节点传输

当回调接收到发现事件时,更新节点的可用传输:

// 示例:在状态管理中更新节点传输
const localDiscoveryCallback = (discoveredNodeData) => {
const { nodeId, transportDetails } = discoveredNodeData;

// transportDetails 结构:
// {
// type: "local",
// metadata: {
// baseUrl: "http://192.168.1.100" // 节点的本地 IP
// }
// }

// 在存储中查找该节点
const node = findNodeById(nodeId);

if (node) {
// 若不存在则将 availableTransports 初始化为 Record
node.availableTransports = node.availableTransports || {};

// 添加或更新本地传输配置
// availableTransports 的类型是 Record<ESPTransportMode, ESPTransportConfig>
node.availableTransports[transportDetails.type] = transportDetails;

console.log(
`Node ${nodeId} is now available locally at ${transportDetails.metadata.baseUrl}`
);
}
};

传输优先级

设置传输顺序

setTransportOrder 方法用于定义 SDK 与节点通信(例如设置设备参数)时应使用的传输优先级。

import { ESPRMBase, ESPTransportMode } from "@espressif/rainmaker-base-sdk";

// 定义传输优先级:先尝试本地,回退到云端
const transportOrder = [
ESPTransportMode.local, // 最高优先级
ESPTransportMode.cloud, // 回退
];

try {
ESPRMBase.setTransportOrder(transportOrder);
console.log("Transport order set successfully");
} catch (error) {
console.error("Error setting transport order:", error);
}
传输优先级策略
  • 本地优先:设置 [ESPTransportMode.local, ESPTransportMode.cloud],在同一网络时可获得更快的响应。
  • 云端优先:设置 [ESPTransportMode.cloud, ESPTransportMode.local],无论网络位置如何行为更一致。

传输顺序与发现的协同方式

  1. 发现更新 availableTransports:当本地发现找到节点时,会以传输模式为键,将本地传输添加到该节点的 availableTransports 记录中。
  2. SDK 检查传输顺序:当设置设备参数时,SDK 会检查已定义的传输顺序。
  3. SDK 尝试通信:SDK 按顺序基于 availableTransports 记录中的可用项逐一尝试传输。
  4. 回退机制:若首选传输失败,SDK 会自动回退到下一个可用传输。
// 示例流程:
// 1. 将传输顺序设置为本地优先
ESPRMBase.setTransportOrder([ESPTransportMode.local, ESPTransportMode.cloud]);

// 2. 订阅本地发现以填充 availableTransports
userInstance.subscribe(ESPRMEventType.localDiscovery, (data) => {
updateNodeTransport(data.nodeId, data.transportDetails);
});

// 3. 当设置参数时,若本地可用,SDK 会自动使用本地传输
await device.setParamValue("power", true);
// SDK 检查:node.availableTransports[ESPTransportMode.local] 是否存在?若存在则使用!
// 如果本地失败或不可用,SDK 将回退到云端

节点更新事件

订阅节点更新事件以接收节点状态变更的实时通知:

const nodeUpdateCallback = (updateData) => {
console.log("Node update received:", updateData);

// updateData 包含以下信息:
// - 哪个节点被更新
// - 哪些参数发生了变化
// - 新的参数值

// 根据上述信息更新界面或状态
handleNodeUpdate(updateData);
};

try {
userInstance.subscribe(ESPRMEventType.nodeUpdates, nodeUpdateCallback);
console.log("Subscribed to node updates");
} catch (error) {
console.error("Error subscribing to node updates:", error);
}
需要通知适配器

节点更新事件需要配置 ESPNotificationAdapter 以启用推送通知。更多信息请查看推送通知文档

管理订阅

订阅事件

为某个事件订阅单个或多个回调:

// 订阅单个回调
userInstance.subscribe(ESPRMEventType.localDiscovery, callback1);

// 一次性订阅多个回调
userInstance.subscribe(ESPRMEventType.localDiscovery, [callback1, callback2]);

取消事件订阅

从事件中移除特定回调:

userInstance.unsubscribe(ESPRMEventType.localDiscovery, callback1);

移除所有回调

移除某个事件的所有回调或移除全部事件的回调:

// 移除某个事件的所有回调
userInstance.removeAllCallbacks(ESPRMEventType.localDiscovery);

// 移除所有事件的回调
userInstance.removeAllCallbacks();

完整示例

下面给出一个完整示例,展示如何在应用中设置事件订阅:

import {
ESPRMBase,
ESPRMEventType,
ESPTransportMode,
} from "@espressif/rainmaker-base-sdk";

// 步骤 1:设置传输顺序(优先本地,加快传输)
ESPRMBase.setTransportOrder([ESPTransportMode.local, ESPTransportMode.cloud]);

// 步骤 2:定义本地发现回调
const handleLocalDiscovery = (discoveredNodeData) => {
const { nodeId, transportDetails } = discoveredNodeData;

console.log(`Node ${nodeId} discovered on local network`);
console.log(`Base URL: ${transportDetails.metadata.baseUrl}`);

// 使用用新的传输更新状态或存储
updateNodeAvailableTransports(nodeId, transportDetails);
};

// 步骤 3:定义节点更新回调
const handleNodeUpdates = (updateData) => {
console.log("Node state changed:", updateData);

// 使用最新节点数据更新界面
refreshNodeData(updateData);
};

// 步骤 4:订阅事件
try {
// 订阅本地发现
userInstance.subscribe(ESPRMEventType.localDiscovery, handleLocalDiscovery);

// 订阅节点更新
userInstance.subscribe(ESPRMEventType.nodeUpdates, handleNodeUpdates);

console.log("All event subscriptions active");
} catch (error) {
console.error("Error setting up subscriptions:", error);
}

// 步骤 5:完成订阅后进行清理(例如应用卸载时)
const cleanup = () => {
userInstance.removeAllCallbacks(ESPRMEventType.localDiscovery);
userInstance.removeAllCallbacks(ESPRMEventType.nodeUpdates);
};

最佳实践

  1. 保持轻量回调:回调应快速更新状态或存储,不要阻塞事件循环。
  2. 优雅处理错误:始终用 try-catch 语句包裹更新状态的代码。
  3. 清理订阅:当组件卸载或不再需要时移除回调。
  4. 使用合适的传输顺序:根据具体使用场景选择传输优先级(本地优先或云端优先)。
  5. 正确更新 availableTransports:确保回调可访问节点存储以更新传输配置。注意 availableTransports 的类型是 Record<ESPTransportMode, ESPTransportConfig>,而不是数组。
  6. 同时测试两种场景:在节点处于本地网络以及仅能通过云端访问时都要测试应用。

相关文档

On this page