---
title: dp-kit - 轻量 DP 功能点处理工具库，支持复杂类型解析、下发节流防抖与即时更新
summary: dp-kit 是 @ray-js/panel-sdk（1.7.0+）提供的 SDM 拦截器工具库，通过 createDpKit 创建。核心能力包括：通过 protocols 自定义 parser/formatter，自动解析/反解析复杂类型 DP（如 colour_data→hue/saturation/value）；sendDpOption 支持 throttle 节流、debounce 防抖、delay 延迟、checkRepeat 重复过滤、ordered 顺序下发；immediate 即时更新（下发后立即刷新 UI 无需等待上报）；ignoreDpDataResponse 忽略设备上报响应（支持 whiteDpCodes 白名单、timeout 防抖超时、customRule 自定义规则）；synchronizeDevProperty 云端 DP 状态同步（支持 blackDpCodes 黑名单、defaultState 默认值）；onBeforeSendDp/onAfterSendDp 下发前后钩子。搭配 useStructuredProps/useStructuredActions 使用。typings/sdm.d.ts 提供全局 TS 类型声明。
questions:
  - dp-kit 自 @ray-js/panel-sdk 哪个版本加入（1.7.0），通过 createDpKit 如何创建并注入 SmartDeviceModel？
  - protocols 如何通过 parser/formatter 配置复杂类型 DP 的解析规则（如将 colour_data 解析为 hue/saturation/value）？
  - protocols 如何通过自定义 parser/formatter 函数处理非标准格式的 DP 数据（如 custom_raw_dp）？
  - sendDpOption 的 throttle、debounce、delay、checkRepeat、ordered 分别控制什么下发行为？
  - "immediate 设为 true 后下发会立即更新 UI，此时 onDataChange 事件的 __from__: 'dp-kit' 有什么用？"
  - ignoreDpDataResponse 的 whiteDpCodes、timeout（默认 10000ms）和 customRule 三种配置方式的优先级关系是什么？
  - synchronizeDevProperty 如何在退出面板重新进入时从云端拉取 DP 状态，blackDpCodes 和 defaultState 怎么配置？
  - typings/sdm.d.ts 全局类型声明文件如何为 useProps、useStructuredProps、useActions、useStructuredActions 提供 TS 类型推导？
  - useStructuredProps 获取结构化数据与 useProps 获取原始数据有什么区别（如 colour_data 返回对象 vs 返回十六进制字符串）？
  - onBeforeSendDp 和 onAfterSendDp 钩子在 publishDps 流程中的执行时机分别是什么？
---

# dp-kit

<Alert type="info">
dp-kit 自 @ray-js/panel-sdk@1.7.0 开始加入
</Alert>

轻量的设备面板 DP 功能点处理工具库，内置支持复杂类型 DP 功能点解析、下发选项 (sendOptions) 增强，以及即时更新等能力。

<Image src="/images/panel/sdm-interceptor-dp-kit.gif" />

## 什么时候需要 dp-kit？

✅ **适合使用**：
- 产品有复杂类型 DP 功能点（如 raw/string 类型的 `colour_data` 需要解析为 `hue / saturation / value`）
- 需要下发节流、防抖、延迟等控制
- 需要下发后立即更新 UI（`immediate` 模式）
- 需要忽略设备上报响应 + 云端 DP 状态同步
- 需要在下发前后注入自定义逻辑（`onBeforeSendDp` / `onAfterSendDp`）

❌ **不需要使用**：
- 产品只有简单 DP 功能点类型（`bool / enum / value`），直接使用 `useProps + useActions` 即可
- 不需要任何下发增强能力

## 接入指南

### Step 1: 配置产品 DP 功能点描述文件

> `src/devices/schema.ts`

可参考 [创建 SDM](/cn/miniapp/solution-panel/ability/common/sdm/usage#devicesschemats)

### Step 2: 配置复杂 DP 解析文件（可选）

> `src/devices/protocols.ts`

- 这一步对应 createDpKit 的 `protocols` 字段，用来自定义复杂 DP 功能点的解析与反解析规则（若当前产品不存在复杂 DP 数据，可以跳过）

```ts | pure
export const protocols = {
  colour_data: {
    parser: (dpValue) => ({
      hue: parseInt(dpValue.slice(0, 4), 16),
      saturation: parseInt(dpValue.slice(4, 8), 16),
      value: parseInt(dpValue.slice(8, 12), 16),
    }),
    formatter: ({ hue, saturation, value }) =>
      `${hue.toString(16).padStart(4, '0')}${saturation
        .toString(16)
        .padStart(4, '0')}${value.toString(16).padStart(4, '0')}`,
  },
};
```

### Step 3: 根据业务场景生成 dp-kit

> `src/devices/index.ts`

```ts | pure
import { SmartDeviceModel, createDpKit } from '@ray-js/panel-sdk';
import { protocols } from '@/devices/protocols';
import { defaultSchema } from '@/devices/schema';

type SmartDeviceSchema = typeof defaultSchema;

export const dpKit = createDpKit<SmartDeviceSchema>({ protocols });

const options = {
  interceptors: dpKit.interceptors,
};

export const devices = {
  common: new SmartDeviceModel<SmartDeviceSchema>(options),
};
```

### Step 4: 初始化 dp-kit 复杂 DP 协议数据（可选）

> `src/app.tsx`

- 接入 `dpKit.init` 初始化复杂 DP 协议数据方法（若不需要复杂数据，可不调用）

### Step 5: 全局类型定义接入（可选）

> `typings/sdm.d.ts`

- 推荐直接参考最新模板文件：
  [PublicSdmTemplate/typings/sdm.d.ts](https://github.com/Tuya-Community/tuya-ray-materials/blob/main/template/PublicSdmTemplate/typings/sdm.d.ts)
- 按当前项目实际情况，将模板中的 `@/devices/schema`、`@/devices/protocols` 等引用路径调整为你的工程路径即可
- 若不需要 TS 类型自动提示，可以跳过这一步

### Step 6: 复杂 DP 协议数据获取及下发

> `src/pages/home/index.tsx`

- `useStructuredProps` hooks 接入获取复杂 DP 协议数据
- `useStructuredActions` hooks 接入下发复杂 DP 协议数据

```tsx | pure
import _ from 'lodash-es';
import React from 'react';
import { View } from '@ray-js/ray';
import { useStructuredProps, useStructuredActions } from '@ray-js/panel-sdk';

export default function Home() {
  const colour = useStructuredProps((props) => props.colour_data);
  const actions = useStructuredActions();
  return (
    <View
      style={{ flex: 1 }}
      onClick={() => {
        actions.colour_data.set({
          hue: _.random(0, 360),
          saturation: _.random(0, 1000),
          value: _.random(0, 1000),
        });
      }}
    >
      <View>hue: {colour.hue}</View>
      <View>saturation: {colour.saturation}</View>
      <View>value: {colour.value}</View>
    </View>
  );
}
```

## API

createDpKit 完整 API 参考和类型定义，请查看 [createDpKit API 文档](/cn/miniapp/solution-panel/ability/common/sdm/interceptors/dpkit/createDpKit)。

以下是 createDpKit 各配置项的使用说明和示例。

### 复杂 DP 解析配置（可选）

这部分对应 createDpKit 的 `protocols` 字段，用来指定复杂 DP 功能点的解析方式。配置后会自动解析 & 反解析这类 DP 功能点，无需再在业务代码里进行处理。

```ts | pure
const dpKit: Middleware = createDpKit<SmartDeviceSchema>({
  protocols: {
    colour_data: {
      parser: (dpValue) => ({
        hue: parseInt(dpValue.slice(0, 4), 16),
        saturation: parseInt(dpValue.slice(4, 8), 16),
        brightness: parseInt(dpValue.slice(8, 12), 16),
      }),
      formatter: ({ hue, saturation, brightness }) =>
        `${hue.toString(16).padStart(4, '0')}${saturation
          .toString(16)
          .padStart(4, '0')}${brightness.toString(16).padStart(4, '0')}`,
    },

    custom_raw_dp: {
      parser: (dpValue) => {
        // 自定义解析
      },

      formatter: (dpValue) => {
        // 自定义格式化
      },
    },
  },
});

/**
 * 获取 colour_data DP 功能点数据
 * useProps(props => props.colour_data) = 000003e803e8
 * useStructuredProps(props => props.colour_data) = { hue: 0, saturation: 1000, brightness: 1000 }
 */

/**
 * 下发 colour_data DP 功能点数据
 * const actions = useActions(); => actions.colour_data.set('000003e803e8');
 * const actions = useStructuredActions(); => actions.colour_data.set({ hue: 0, saturation: 1000, brightness: 1000 });
 */
```

如果数据结构比较固定，也可以改用更简短的映射配置；但在教程场景里，优先使用 `parser / formatter` 通常更直观。

### 下发选项 (sendOptions)（可选）

下发 DP 功能点的选项，对应 createDpKit 的 `sendDpOption` 字段。若配置在 createDpKit 中，将影响后续所有的下发指令。

> 完整类型定义请查看 [createDpKit API > SendDpOption](/cn/miniapp/solution-panel/ability/common/sdm/interceptors/dpkit/createDpKit#SendDpOption)

| 属性 | 类型 | 默认值 | 说明 |
|-----|------|-------|------|
| `immediate` | `boolean` | `false` | 下发后立即更新 UI，无需等待设备上报 |
| `throttle` | `number` | `0` | 下发节流 (ms) |
| `debounce` | `number` | `0` | 下发防抖 (ms)，与节流冲突 |
| `delay` | `number` | `0` | 延迟下发 (ms) |
| `checkRepeat` | `boolean` | `false` | 重复值不下发 |
| `ordered` | `boolean` | `false` | 多个 DP 功能点按顺序下发 |
| `ignoreDpDataResponse` | `boolean \| IgnoreDpChangeInterceptorOptions` | `false` | 忽略设备上报响应（1.11.0+） |
| `synchronizeDevProperty` | `boolean \| DevPropInterceptorOptions` | `false` | 云端 DP 状态同步（1.11.0+） |
| `protocols` | `Record<string, CustomRawDpMap>` | - | 单次下发临时协议转换 |

**ignoreDpDataResponse 对象配置**：

| 属性 | 类型 | 默认值 | 说明 |
|-----|------|-------|------|
| `whiteDpCodes` | `string[]` | - | 白名单 DP 功能点，不会忽略上报 |
| `timeout` | `number` | `10000` | 防抖超时 (ms)，超时后才触发 `dpDataChange`（1.14.0+） |
| `customRule` | `function` | - | 自定义忽略规则，优先级最高（1.14.0+） |
| `debug` | `boolean` | - | 开启调试日志 |

**synchronizeDevProperty 对象配置**：

| 属性 | 类型 | 说明 |
|-----|------|------|
| `blackDpCodes` | `string[]` | 黑名单 DP 功能点，不同步到云端 |
| `defaultState` | `object \| function` | 云端数据为空时的默认值，支持异步 |

例如，如果期望应用内的下发都具有 600ms 的节流，您可以：

```ts | pure
const dpKit = createDpKit<SmartDeviceSchema>({
  sendDpOption: {
    throttle: 600,
  },
});
```

或者，如果期望 DP 功能点不再等到设备上报后才更新，您可以：

```ts | pure
const dpKit = createDpKit<SmartDeviceSchema>({
  sendDpOption: {
    immediate: true,
  },
});
```

注意，通过 dp-kit `immediate` 即时更新的 DP 功能点数据，在 SDM 内部 `onDataChange` 事件触发时会额外附带一个 `__from__: dp-kit` 的回调值，方便业务判断或区分实际 DP 功能点上报自行处理，原始 [onDpDataChange](/cn/miniapp/solution-panel/ability/common/sdm/api/onDpDataChange) 事件则不会被触发。

此外，如果您想针对单个 DP 功能点下发不再等到设备上报后才更新，那么您可以：

```ts | pure
const actions = useActions();
actions.power.toggle({ immediate: true });
```

但仅使用 `immediate` 在设备上报时还会触发一次更新，容易导致 UI 闪烁。如果期望忽略设备上报的响应，即仅下发，您可以：

```ts | pure
const dpKit = createDpKit<SmartDeviceSchema>({
  sendDpOption: {
    immediate: true,
    ignoreDpDataResponse: true, // 忽略设备上报响应
  },
});
```

或者，有部分 DP 功能点需要进行响应，可以使用白名单配置：

```ts | pure
const dpKit = createDpKit<SmartDeviceSchema>({
  sendDpOption: {
    immediate: true,
    ignoreDpDataResponse: {
      whiteDpCodes: ['switch'], // switch DP 功能点上报时进行响应，其他 DP 功能点上报会忽略
    },
  },
});
```

您也可以使用 `timeout` 参数配置防抖超时时间：

```ts | pure
const dpKit = createDpKit<SmartDeviceSchema>({
  sendDpOption: {
    immediate: true,
    ignoreDpDataResponse: {
      timeout: 1000 * 5, // 5 秒超时，超过此时间才触发 dpDataChange
    },
  },
});
```

或者使用 `customRule` 自定义忽略规则（优先级最高，配置后 `whiteDpCodes` 和 `timeout` 将失效）：

```ts | pure
const dpKit = createDpKit<SmartDeviceSchema>({
  sendDpOption: {
    immediate: true,
    ignoreDpDataResponse: {
      customRule: (dpState, lastSendTimestamp) => {
        // 自定义逻辑：仅响应特定 dp 或时间条件
        if (dpState.switch !== undefined) {
          return true; // switch dp 始终响应
        }
        if (lastSendTimestamp === null) {
          return true; // 首次上报响应
        }
        const timeDiff = Date.now() - lastSendTimestamp;
        return timeDiff > 8000; // 超过 8 秒才响应
      },
    },
  },
});
```

当忽略设备上报响应时，退出面板重新进入后，设备上一次的状态会无法获取，您可以使用 `synchronizeDevProperty` 实现拉取云端 DP 状态：

```ts | pure
const dpKit = createDpKit<SmartDeviceSchema>({
  sendDpOption: {
    immediate: true,
    ignoreDpDataResponse: {
      whiteDpCodes: ['switch'],
    },
    synchronizeDevProperty: true, // 同步云端设备存储属性
  },
});
```

当每次下发 DP 功能点时，会自动写入到云端设备存储数据。退出面板重新进入时，会做一次 DP 状态初始化，将云端设备存储数据拉取到面板。

同样地，您也可以配置哪些 DP 功能点不需要进行同步：

```ts | pure
const dpKit = createDpKit<SmartDeviceSchema>({
  sendDpOption: {
    synchronizeDevProperty: {
      blackDpCodes: ['switch'], // switch DP 功能点不会做云端数据同步
    },
  },
});
```

云端数据为空时，可以配置默认值：

```ts | pure
const dpKit = createDpKit<SmartDeviceSchema>({
  sendDpOption: {
    ignoreDpDataResponse: true,
    synchronizeDevProperty: {
      defaultState: {
        switch: false, // switch DP 功能点默认值配置（如果云端数据为空）
      },
    },
  },
});
```

### onBeforeSendDp / onAfterSendDp（可选）

下发 DP 前/后的钩子（在 `publishDps` 之前/之后），建议传入 SmartDeviceSchema 以确保获得正确的 type。

```ts | pure
export const dpKit = createDpKit<SmartDeviceSchema>({
  onBeforeSendDp(dpState) {
    console.log('=== onBeforeSendDp', dpState);
  },
  onAfterSendDp(dpState) {
    console.log('=== onAfterSendDp', dpState);
  },
});
```

## 进阶阅读

### logger 拦截器

> dp-kit 内置了 logger 拦截器，可在控制台查看 DP 下发和上报日志。

[logger 文档](/cn/miniapp/solution-panel/ability/common/sdm/interceptors/logger)

### matter-kit 拦截器

> 如果需要同时处理 Matter 设备，可搭配 matter-kit 使用。

[matter-kit 文档](/cn/miniapp/solution-panel/ability/common/sdm/interceptors/matterkit/usage)

### SmartDeviceModel 使用指南

> dp-kit 基于 SmartDeviceModel 的拦截器机制工作。

[SmartDeviceModel 文档](/cn/miniapp/solution-panel/ability/common/sdm/usage)

### 使用 SDM 拦截器和 DP 自定义协议解析

> 一个基于 dp-kit 的自定义拦截器和自定义协议解析的教程示例。

[教程地址](https://developer.tuya.com/cn/miniapp-codelabs/codelabs/sdm-transformer/index.html#1)

### Beacon 设备面板模板

> 一个基于 dp-kit 内置功能实现的 Beacon 设备面板教程示例。

[教程地址](https://developer.tuya.com/cn/miniapp-codelabs/codelabs/panel-sdm-dpkit-beacon/index.html#1)
