/// import EventEmitter from 'events'; import SmartDeviceModel, { SmartDeviceModelInterceptors } from './SmartDeviceModel'; import { LogConfig } from './utils'; import type { DpDataChangeParams, DeviceOnlineStatusUpdateParams, DeviceInfoUpdatedParams, NetworkStatusChangeParams, BluetoothAdapterStatusChangeParams } from './types'; type FailedDeviceInfo = { /** 设备实例在管理器中的唯一键名 */ key: string; /** 设备 ID */ deviceId: string; /** 初始化错误 */ error: Error; }; type AddConfig = { /** 设备实例在管理器中的唯一键名 */ key: string; /** 设备 ID */ deviceId: string; /** 该设备实例的拦截器配置,常见用于搭配 dp-kit 实现结构化 DP 转换,选填,默认不配置 */ interceptors?: SmartDeviceModelInterceptors; /** 该设备实例的日志配置,选填,默认不配置 */ logConfig?: LogConfig; }; type BatchAddOptions = { /** 并发初始化数量,默认 5(避免一次性批量调用过多 API 导致异常) */ concurrency?: number; }; export type SmartDevicesManagerChangeEvent = { type: 'add'; key: string; instance: SmartDeviceModel; } | { type: 'init'; key: string; instance: SmartDeviceModel; } | { type: 'initComplete'; } | { type: 'initProgress'; progress: { total: number; initialized: number; keys: string[]; }; } | { type: 'delete'; key: string; } | { type: 'dpDataChange'; key: string; instance: SmartDeviceModel; data: DpDataChangeParams; } | { type: 'deviceOnlineStatusUpdate'; key: string; instance: SmartDeviceModel; data: DeviceOnlineStatusUpdateParams; } | { type: 'deviceInfoUpdated'; key: string; instance: SmartDeviceModel; data: DeviceInfoUpdatedParams; } | { type: 'networkStatusChange'; data: NetworkStatusChangeParams; } | { type: 'bluetoothAdapterStateChange'; data: BluetoothAdapterStatusChangeParams; }; export type BatchAddResult = { /** * 成功初始化的设备实例映射 * @typeOverride success Record */ success: Record>; /** * 初始化失败的设备列表 */ failed: FailedDeviceInfo[]; }; /** * @public * 多设备管理器:统一管理多个设备实例,负责批量初始化、全局事件路由、全局状态缓存,以及 add / batchAdd / delete 等标准化操作。 * 构造器本身零副作用,不会注册任何全局监听。 * @since @ray-js/panel-sdk 1.16.0 * @example 创建多设备管理器 * ```ts * const manager = new SmartDevicesManager(); * manager.init(); * manager.add({ key: 'lamp1', deviceId: '1234567890' }); * manager.add({ key: 'lamp2', deviceId: '1234567891' }); * ``` */ export declare class SmartDevicesManager extends EventEmitter { private _instances; /** * deviceId -> key 的映射,用于 O(1) 路由事件到具体设备实例 */ private _deviceIdMap; /** * 全局事件监听器是否已注册 */ private _globalListenersRegistered; private _globalStateCache; private _globalStateFetching; private _logConfig?; /** * 构造器零副作用:仅初始化内部状态,不注册任何全局监听。 * 使用前需调用 init() 开始监听;卸载时调用 destroy(),再次使用可重新 init()。 * @public * @since @ray-js/panel-sdk 1.16.0 * @param options - 配置选项 * @typeOverride options { logConfig?: LogConfig } * @example 实例化设备管理器 * ```ts * import { SmartDevicesManager, setSdmLogScopeMuted } from '@ray-js/panel-sdk'; * * // 默认配置 * const deviceManager = new SmartDevicesManager(); * * // 开启详细日志,并设置 scope 以便在必要时静音 * const deviceManager2 = new SmartDevicesManager({ * logConfig: { level: 'VERBOSE', scope: 'multi-device' }, * }); * * // 在某些场景下(如进入单设备页)静音多设备日志 * setSdmLogScopeMuted('multi-device', true); * // 返回多设备页时恢复 * setSdmLogScopeMuted('multi-device', false); * ``` */ constructor(options?: { logConfig?: LogConfig; }); /** * 开始监听全局事件(Ray 全局 DP/上下线等),幂等调用。 * @remarks `add` / `batchAdd` 会自动调用 `init()`,因此如需在添加设备前预先注册全局监听(如监听 `change` 事件),可先手动调用一次 `init()`。 * @public * @since @ray-js/panel-sdk 1.16.0 * @returns void * @example 预先注册全局监听 * ```ts * import React, { useEffect } from 'react'; * import { SmartDevicesManager, SdmProvider } from '@ray-js/panel-sdk'; * * const deviceManager = new SmartDevicesManager(); * * export default function App({ children }) { * useEffect(() => { * deviceManager.init(); // 开始监听全局事件 * return () => { * deviceManager.destroy(); // 组件卸载时清理 * }; * }, []); * * return ( * * {children} * * ); * } * ``` */ init(): void; /** * 订阅多设备管理器变更事件。 * `SdmProvider` 内部已通过 `change` 事件驱动多设备 Hooks 刷新;常规业务通常无需手动监听。 * 仅在 Provider 外部监听设备状态变化(如全局日志、非 React 组件等场景)时使用。 * @public * @since @ray-js/panel-sdk 1.16.0 * @param event - 事件名,固定为 `change` * @param handler - 事件回调函数 * @typeOverride handler (event: { type: string; [key: string]: any }) => void * @returns 当前 Manager 实例,支持链式调用 * @remarks 常见事件类型包括:`add`、`init`、`initComplete`、`initProgress`、`delete`、`dpDataChange`、`deviceOnlineStatusUpdate` / `deviceInfoUpdated`、`networkStatusChange`、`bluetoothAdapterStateChange`。 * @example 监听不同事件类型并读取返回结构 * ```ts * manager.on('change', event => { * switch (event.type) { * case 'add': * case 'init': * console.log(event.key, event.instance); * break; * case 'initProgress': * console.log(event.progress.total, event.progress.initialized, event.progress.keys); * break; * case 'dpDataChange': * case 'deviceOnlineStatusUpdate': * case 'deviceInfoUpdated': * console.log(event.key, event.instance, event.data); * break; * case 'networkStatusChange': * case 'bluetoothAdapterStateChange': * console.log(event.data); * break; * case 'initComplete': * console.log('all initialized'); * break; * case 'delete': * console.log(event.key); * break; * } * }); * ``` */ on(event: 'change', handler: (event: SmartDevicesManagerChangeEvent) => void): this; /** * 取消订阅多设备管理器变更事件。 * 需传入与 `on` 时相同的事件名和回调引用。 * @public * @since @ray-js/panel-sdk 1.16.0 * @param event - 事件名,固定为 `change` * @param handler - 事件回调函数 * @typeOverride handler (event: { type: string; [key: string]: any }) => void * @returns 当前 Manager 实例,支持链式调用 * @remarks 注意回调引用保持一致,否则无法取消监听。 * @example 取消监听设备变更事件 * ```ts * const handleChange = event => { * console.log(event.type); * }; * * manager.on('change', handleChange); * manager.off('change', handleChange); * ``` */ off(event: 'change', handler: (event: SmartDevicesManagerChangeEvent) => void): this; /** * 统一日志:监听 change 事件,以与 SmartDeviceModel 一致的格式输出一条带 key/type 的日志 * 使用 try/catch 避免日志逻辑抛错影响其他 change 监听器(如 SdmProvider) */ private __changeLogHandler__; /** * 注入 Manager 级 publishDps request interceptor(避免包实例方法导致递归) * 同时兼容两类路径: * - instance.publishDps(...) * - instance.model.actions.xxx.set/toggle(...) */ private __injectManagerPublishDpsInterceptor__; /** * 注册全局事件监听器(仅一次) * 多设备场景下,统一监听事件并路由到具体设备,避免每个设备独立注册导致的性能问题 */ private _registerGlobalEventListeners; /** * 全局 DP 数据变化处理器(路由到具体设备实例) */ private __globalDpDataChangeHandler__; /** * 全局设备上下线状态处理器 */ private __globalDeviceOnlineStatusHandler__; /** * 全局设备信息更新处理器 */ private __globalDeviceInfoUpdatedHandler__; /** * 全局网络状态变化处理器 */ private __globalNetworkStatusChangeHandler__; /** * 全局蓝牙适配器状态变化处理器 */ private __globalBluetoothAdapterStateChangeHandler__; /** * 获取全局网络状态(懒加载 + 缓存) * 首次调用时异步获取,后续设备直接使用缓存 */ private getNetworkStatusShared; /** * 获取全局蓝牙状态(懒加载 + 缓存) */ private getBluetoothStatusShared; /** * 添加单个设备实例并完成初始化。 * 若尚未 init() 会先自动 init(),保证向后兼容。 * 常见场景是动态添加单台关联设备;若 `deviceId` 已存在则抛出错误。 * @public * @since @ray-js/panel-sdk 1.16.0 * @param config - 设备配置 * @returns 初始化完成的设备实例 * @typeOverride returns Promise * @remarks 若 deviceId 已存在则会抛出错误 * @example 动态添加单个设备 * ```ts * import { SmartDevicesManager, createDpKit } from '@ray-js/panel-sdk'; * * const deviceManager = new SmartDevicesManager(); * const dpKit = createDpKit({ protocols }); * * const lamp = await deviceManager.add({ * key: 'lamp1', * deviceId: 'xxx_device_id', * interceptors: dpKit.interceptors, * logConfig: { level: 'VERBOSE' }, * }); * * lamp.getDevInfo(); * ``` */ add(config: AddConfig): Promise>; /** * 批量向多设备管理器中添加设备实例。内部会先批量拉取设备信息(单次网络请求),再按 `concurrency` 并发初始化,支持部分失败并在返回结果中区分成功与失败列表。 * 每台设备都可独立配置 `interceptors` 与 `logConfig`。 * @public * @since @ray-js/panel-sdk 1.16.0 * @param configs 设备配置列表 * @param options 配置选项 * @returns 包含 success 与 failed 的结果对象;其中 success 为成功初始化的设备实例映射,failed 为初始化失败的设备列表 * @example 批量添加设备 * ```ts * import { SmartDevicesManager, createDpKit } from '@ray-js/panel-sdk'; * * const deviceManager = new SmartDevicesManager(); * const dpKit = createDpKit({ protocols }); * * const result = await deviceManager.batchAdd([ * { * key: 'lamp1', * deviceId: 'xxx_device_id_1', * interceptors: dpKit.interceptors, // 搭配 dp-kit 使用结构化 DP * }, * { * key: 'lamp2', * deviceId: 'xxx_device_id_2', * interceptors: dpKit.interceptors, * logConfig: { level: 'VERBOSE' }, // 单独开启此设备的详细日志 * }, * { * key: 'failedDevice', * deviceId: 'invalid_device_id', * }, * ], { concurrency: 5 }); * * if (result.failed.length > 0) { * console.warn('部分设备初始化失败:', result.failed); * } * // batchAdd 返回示例: * { * "success": { * "lamp1": "", * "lamp2": "" * }, * "failed": [ * { * "key": "failedDevice", * "deviceId": "invalid_device_id", * "error": "Device info not found for invalid_device_id" * } * ] * } * ``` */ batchAdd(configs: AddConfig[], options?: BatchAddOptions): Promise; /** * 删除设备实例。 * 从多设备管理器中删除指定 key 对应的设备实例,自动调用该实例的 `destroy()` 并清理内部映射。 * @public * @since @ray-js/panel-sdk 1.16.0 * @param params - 包含要删除的设备 key 的对象 * @returns void * @example 删除单个设备 * ```ts * manager.delete({ key: 'lamp1' }); * ``` */ delete(params: { key: string; }): void; /** * 批量删除多设备管理器中指定 key 列表对应的设备实例,内部对每个 key 依次调用 `delete({ key })`,自动触发实例销毁与内部映射清理。 * @public * @since @ray-js/panel-sdk 1.16.0 * @param keys 设备实例 key 列表 * @returns void * @example 批量删除设备 * ```ts * deviceManager.batchDelete(['lamp1', 'lamp2']); * ``` */ batchDelete(keys: string[]): void; /** * 获取所有已注册设备实例的浅拷贝,以 key 为索引。 * 常用于需要直接操作设备实例而非通过 Hooks 的场景,例如在事件回调中遍历所有设备。 * @public * @since @ray-js/panel-sdk 1.16.0 * @returns 所有设备实例的记录对象 * @typeOverride returns Record * @example 获取设备实例集合 * ```ts * const instances = manager.getDevices(); * Object.values(instances).forEach(device => { * device.publishDps({ switch_led: true }); * }); * ``` */ getDevices(): { [x: string]: SmartDeviceModel>; }; /** * 检查所有已添加设备是否已初始化完成。 * @public * @since @ray-js/panel-sdk 1.16.0 * @returns 所有的设备实例是否已初始化 * @example 检查所有设备是否已初始化 * ```ts * const allInitialized = manager.isAllInitialized(); * console.log(allInitialized ? '全部初始化完成' : '仍在初始化中'); * ``` */ isAllInitialized(): boolean; /** * 获取初始化进度(内部使用) */ private getInitProgress; /** * 检查指定设备是否已初始化(内部使用) */ private isInitialized; /** * 销毁多设备管理器:注销所有全局事件监听器、移除全部 `change` 事件订阅、销毁并清理所有设备实例与内部映射。 * @public * @since @ray-js/panel-sdk 1.16.0 * @returns void * @remarks 在 useEffect return 或组件 componentWillUnmount 中务必调用 destroy(),避免全局事件监听残留或内存泄漏。 * @example 销毁设备管理器 * ```ts * // 页面卸载或清空设备时调用 * manager.destroy(); * ``` */ destroy(): void; } export {};