import { DpMap, DpMapItem } from '@ray-js/tuya-dp-transform'; import { GetSmartDeviceModelProps, ReadonlyDpSchemaList } from './SdmModel'; import SmartDeviceModel, { SmartDeviceModelInterceptors } from '../SmartDeviceModel'; import { PublishDpsOptions, publishDps } from '../../kit/publishDps'; import { ConstructorProps } from '../../types/utilities'; import { OnDeviceInfoUpdatedInterceptor, OnDpDataChangeInterceptor, PublishDpsInterceptor } from './interceptors'; import { IgnoreDpChangeInterceptorOptions } from '../interceptors/dp-kit/utils/ignoreDpChangeInterceptor'; import { DevPropInterceptorOptions } from '../interceptors/dp-kit/utils/devPropInterceptor'; /** * createDpKit 的返回结果,包含一组可直接挂到 SmartDeviceModel 的拦截器, * 以及初始化结构化 DP 状态所需的 `init` / `destroy` 生命周期方法。 * @remarks * 常见用法是把 `interceptors` 传给 SmartDeviceModel 构造参数, * 在设备初始化完成后调用 `init` 注入结构化 DP 初始值,并在销毁阶段调用 `destroy` 清理内部定时器。 */ export type CreateDpKitResult = { /** * 初始化设备状态,在需要搭配 useStructuredProps 时须在设备模型初始化完毕后调用 * @typeOverride init (device: any) => void */ init: (device: SmartDeviceModel) => void; /** * dp-kit 默认拦截器配置 * @typeOverride interceptors Record */ interceptors: SmartDeviceModelInterceptors; /** * dp-kit onDeviceInfoUpdated 拦截器,如需单独搭配使用时可考虑 * @typeOverride onDeviceInfoUpdated (ctx: any) => (next: (data: any) => any) => (data: any) => any */ onDeviceInfoUpdated: OnDeviceInfoUpdatedInterceptor; /** * dp-kit onDpDataChange 拦截器,如需单独搭配使用时可考虑 * @typeOverride onDpDataChange (ctx: any) => (next: (data: any) => any) => (data: any) => any */ onDpDataChange: OnDpDataChangeInterceptor; /** * dp-kit publishDps 拦截器,如需单独搭配使用时可考虑 * @typeOverride publishDps (ctx: any) => (next: (dpState: Record, options?: SendDpOption) => any) => (dpState: Record, options?: SendDpOption) => any */ publishDps: PublishDpsInterceptor; /** * 销毁 dp-kit,清理 flush 定时器、节流和防抖映射等资源。 * 应在 SmartDeviceModel 销毁时调用(如 SdmProvider 的 useEffect cleanup 中) */ destroy: () => void; }; /** * createDpKit 的配置项,统一描述协议解析、全局下发选项与前后置 hooks。 * @remarks * `protocols` 负责把 raw/string 等复合 DP 映射为结构化对象, * `sendDpOption` 用于声明全局默认的下发行为, * `onBeforeSendDp` / `onAfterSendDp` 则适合补充埋点、兜底转换或业务副作用。 */ export type CreateDpKitOptions> = { /** * DP 协议映射表,将复合字符串类型的 DP(如 colour_data)拆解为结构化对象。 * key 为 dpCode,value 为自定义 Transformer * * 需实现 parser/formatter:`{ colour_data: new ColourTransformer() }` * * - parser(raw: string) => T — 将设备上报的原始字符串解析为结构化对象 * - formatter(data: T) => string — 将结构化对象序列化为下发给设备的字符串 * * 注册后可通过 useStructuredProps / useStructuredActions 读写结构化数据 * * @typeOverride protocols Record */ readonly protocols?: Partial>; /** * DP 下发选项 */ readonly sendDpOption?: SendDpOption; /** * 下发 DP 前的钩子 * @typeOverride onBeforeSendDp (dpState: DpState) => any */ readonly onBeforeSendDp?: ( /** * 当次下发的 DP */ dpState: Partial) => any; /** * 下发 DP 前的钩子 * @typeOverride onAfterSendDp (dpState: DpState) => any */ readonly onAfterSendDp?: ( /** * 当次下发的 DP */ dpState: Partial) => any; }; /** * DP 下发选项,可作为 createDpKit 的全局默认配置,也可在单次 publishDps / action 调用时覆盖。 * 全局 `sendDpOption` 适合声明产品级默认行为; * 单次下发传入的 options 适合临时覆盖节流、防抖、协议解析或乐观更新策略。 * 注:依赖 dp-kit 拦截器才可使用。 */ export type SendDpOption = { /** * 是否立即触发 state 更新,必须依赖 dp-kit 拦截器才可使用 * * @defaultValue false */ readonly immediate?: boolean; /** * 是否忽略 DP 功能点上报,默认 false * @defaultValue false * @since 1.11.0 */ readonly ignoreDpDataResponse?: boolean | IgnoreDpChangeInterceptorOptions>; /** * 是否将 dpData 和云端设备属性同步,默认 false * @defaultValue false * @since 1.11.0 */ readonly synchronizeDevProperty?: boolean | DevPropInterceptorOptions>; /** * 多个 DP 是否按对象里的顺序下发,必须依赖 dp-kit 拦截器才可使用,默认 false * * @defaultValue false */ readonly ordered?: boolean; /** * 是否进行重复值判断不下发,必须依赖 dp-kit 拦截器才可使用,默认 false * 与当前 `dpState` 进行比较,重复值检出不下发 * * @defaultValue false */ readonly checkRepeat?: boolean; /** * 下发 DP 的过时时间,必须依赖 dp-kit 拦截器才可使用 */ /** * 延迟下发,必须依赖 dp-kit 拦截器才可使用,默认 0,单位 ms * * @defaultValue 0 */ readonly delay?: number; /** * 下发节流 (与防抖冲突),必须依赖 dp-kit 拦截器才可使用,默认 0,单位 ms * * @defaultValue 0 */ readonly throttle?: number; /** * 下发防抖 (与节流冲突),必须依赖 dp-kit 拦截器才可使用,默认 0,单位 ms * * @defaultValue 0 */ readonly debounce?: number; /** * 单次下发时临时指定的 DP 协议转换器,必须依赖 dp-kit 拦截器才可使用。 * key 为 dpCode,value 为 `{ parser, formatter }` 对象: * - parser(dpValue: string) => any — 将原始 DP 字符串解析为结构化对象 * - formatter(parsedValue: any) => string — 将结构化对象序列化为 DP 字符串 * 仅影响本次调用,不覆盖 createDpKit 中的全局 protocols 配置 */ readonly protocols?: Record; }; /** * 自定义 DP 协议转换器,用于将原始 DP 字符串与结构化对象互转。 * 适用于 raw/string 类型的复合 DP(如灯的 colour_data "00ff003e8"), * 将单个字符串拆解为多个语义字段(如 { hue, saturation, value })。 * @remarks * 当 DSL 无法表达协议格式,或者协议读写逻辑需要复用既有 parser / formatter 时, * 可以直接实现这两个函数并交给 `protocols` 或单次下发的 `options.protocols` 使用。 */ export type CustomRawDpMap = { /** 将设备上报的原始 DP 字符串解析为结构化对象 */ parser?: (dpValue: string) => any; /** 将结构化对象序列化为下发给设备的 DP 字符串 */ formatter?: (parsedDpValue: any) => string; }; export type EnhancedDpMap = DpMap | CustomRawDpMap; export type SmartDeviceModelOptions = ConstructorProps; export type PublishDpsParams = Parameters; interface DpTransform { /** * 协议解析 * 返回对应的数据对像 */ parser: (...args: any) => any; /** * 协议反解析 * 将数据转为协议数据 */ formatter: (...args: any) => any; } export type GetStructuredDpStateKVFromJSON = { [D in T[number]['name']]: Extract['defaultValue']; }; export type GetStructuredDpStateKVFromFormatter = ReturnType; export type DpKitProtocols = Record; export type GetStructuredDpState = { [D in keyof T]: T[D] extends DpMapItem[] ? GetStructuredDpStateKVFromJSON : T[D] extends DpTransform ? GetStructuredDpStateKVFromFormatter : never; }; export type GetStructuredActionsKVFromJSON = { /** * 下发 DP 点 * @param value - DP 对应的值 */ set: (value: { [D in T[number]['name']]: Extract['defaultValue']; }, options?: PublishDpsOptions) => Promise; }; export type GetStructuredActionsKVFromFormatter = { /** * 下发 DP 点 * @param value - DP 对应的值 */ set: (value: Parameters['0'], options?: PublishDpsOptions) => Promise; }; export type GetStructuredActions = { [D in keyof T]: T[D] extends DpMapItem[] ? GetStructuredActionsKVFromJSON : T[D] extends DpTransform ? GetStructuredActionsKVFromFormatter : never; }; export {};