---
title:  SDM 智能设备模型使用指南 - 创建、配置与接入
summary: SDM 智能设备模型使用指南 - 创建、配置与接入, 本文介绍了如何在面板小程序中使用 SDM（Smart Device Model）能力，包括创建智能设备模型、定义智能设备描述文件、全局声明智能设备类型、使用 SDM 控制设备等。通过本文的介绍，开发者可以快速掌握如何在面板小程序中使用 SDM 能力，实现智能设备的管理和控制。
questions:
  - 如何通过 SmartDeviceModel 和 SmartGroupModel 创建智能设备模型实例？
  - schema.ts 中的 DP 功能点描述文件需要加 as const 断言的原因是什么？
  - 如何通过 Tuya MiniApp IDE 的设备工具自动注入 schema 到项目中？
  - typings/sdm.d.ts 全局类型声明文件的作用是什么？
  - SdmProvider 在根组件 app.tsx 中的作用是什么，为什么子组件不需要手动调用 init？
  - 如何通过 useProps 获取设备功能点的实时状态？
  - 如何通过 useActions 的 toggle 方法控制设备开关？
  - SmartDeviceModel 和 SmartGroupModel 如何根据设备环境自动切换？
  - devices/index.ts 中使用 isGroupDevice 判断群组环境的目的是什么？
  - 使用 SDM 的完整项目目录结构包含哪些关键文件（devices/index.ts、schema.ts、sdm.d.ts、app.tsx）？
---

# 使用

## 创建 SDM

<Alert type="info">
  以下目录包含了本章节所需要涉及到的所有文件，也可以直接基于 [public-sdm](https://github.com/Tuya-Community/tuya-ray-materials/tree/main/template/PublicSdmTemplate) 示例项目进行开发
</Alert>

<Tree.DirectoryTree
  multiple
  defaultExpandAll
  treeData={[
    {
      title: 'src',
      key: '0-0',
      children: [
        {
          title: 'devices',
          key: '0-0-0',
          isLeaf: false,
          children: [
            { title: 'index.ts', key: '0-0-0-1', isLeaf: true },
            { title: 'schema.ts', key: '0-0-0-2', isLeaf: true },
          ],
        },
        {
          title: 'pages',
          key: '0-0-1',
          isLeaf: false,
          children: [
            {
              title: 'home',
              key: '0-0-1-1',
              isLeaf: false,
              children: [{ title: 'index.tsx', key: '0-0-1-1-1', isLeaf: true }],
            },
          ],
        },
        { title: 'app.tsx', key: '0-0-2', isLeaf: true },
      ],
    },
    {
      title: 'typings',
      key: '0-1',
      children: [{ title: 'sdm.d.ts', key: '0-1-0', isLeaf: true }],
    },
  ]}
/>

### 生成智能设备模型

<Callout type="info" emoji="ℹ️">
  该示例文件位于 devices/index.ts，用于生成智能设备模型以供后续业务项目中使用
</Callout>

```typescript
import { SmartDeviceModel, SmartGroupModel, SmartDeviceSchema } from '@ray-js/panel-sdk';
import { getLaunchOptionsSync } from '@ray-js/ray';

// SmartDeviceSchema 定义来自于 typings/sdm.d.ts，非 TypeScript 开发者可忽略
export const devices = {
  /**
   * 此处建议以智能设备的名称作为键名赋值，
   * 如果想要默认支持基础群组功能，则可以判断当前是否为群组环境来选择使用的智能模型以默认适配
   */
  robot: isGroupDevice
    ? new SmartGroupModel<SmartDeviceSchema>(options)
    : new SmartDeviceModel<SmartDeviceSchema>(options),
};

/**
 * 注意，如果使用了 SdmProvider 则无需手动调用 init 方法，SdmProvider 会自动调用并在设备初始化完毕后再渲染子组件
 */
Object.keys(devices).forEach((k: keyof typeof devices) => {
  devices[k].init();
});
```

### 定义智能设备描述文件

<Callout type="info" emoji="ℹ️">
  该示例文件位于 src/devices/schema.ts，用于定义智能设备的 DP 功能点描述，以便后续业务中可以根据 TS 的类型约束，围绕当前智能设备的功能定义进行开发
</Callout>

```typescript
/**
 * 智能设备模型的 DP 功能点描述
 */
export const defaultSchema = [
  {
    attr: 0,
    canTrigger: true,
    code: 'power',
    defaultRecommend: false,
    editPermission: false,
    executable: true,
    extContent: '',
    iconname: 'icon-dp_power2',
    id: 1,
    mode: 'rw',
    name: '开关',
    property: {
      type: 'bool',
    },
    type: 'obj',
  },
  {
    attr: 0,
    canTrigger: true,
    code: 'mode',
    defaultRecommend: false,
    editPermission: false,
    executable: true,
    extContent: '',
    iconname: 'icon-dp_mode',
    id: 3,
    mode: 'rw',
    name: '清扫模式',
    property: {
      range: [
        'standby',
        'random',
        'smart',
        'wall_follow',
        'mop',
        'spiral',
        'left_spiral',
        'right_spiral',
        'right_bow',
        'left_bow',
        'partial_bow',
        'chargego',
      ],
      type: 'enum',
    },
    type: 'obj',
  },
] as const;
```

<Callout type="info" emoji="ℹ️">
  可通过 Tuya MiniApp IDE 中设备工具里的智能设备模型 Tab 来注入到项目中，详见下图
</Callout>

<Callout type="warning" emoji="⚠️">
  请注意给 schema 加上 as const 断言以便能够正常进行类型推导
</Callout>

<Image src='/images/panel/virtual-device-sdm.png'/>

### 全局声明智能设备类型

<Callout type="info" emoji="ℹ️">
  该示例文件位于 typings/sdm.d.ts，用于全局声明 SDM 相关的类型定义，方便开发者在项目中能一键获得智能设备相关配套 Hooks 的 TS 类型提示，非 TypeScript 开发者可忽略该类型定义文件
</Callout>

<Callout type="warning" emoji="⚠️">
  请注意该步骤必须在上一步智能设备描述文件定义完成后进行，否则会导致 TS 类型推导失败
</Callout>

```typescript
import '@ray-js/panel-sdk';
import { GetStructuredDpState, GetStructuredActions } from '@ray-js/panel-sdk';

type SmartDeviceSchema = typeof import('@/devices/schema').defaultSchema; // 注意变量名
type SmartDeviceProtocols = typeof import('@/devices/protocols').protocols;
type SmartDevices = import('@ray-js/panel-sdk').SmartDeviceModel<SmartDeviceSchema>;

declare module '@ray-js/panel-sdk' {
  export const SdmProvider: React.FC<{
    value: SmartDeviceModel<SmartDeviceSchema>;
    children: React.ReactNode;
  }>;
  export type SmartDeviceInstanceData = {
    devInfo: ReturnType<SmartDevices['getDevInfo']>;
    dpSchema: ReturnType<SmartDevices['getDpSchema']>;
    network: ReturnType<SmartDevices['getNetwork']>;
    bluetooth: ReturnType<SmartDevices['getBluetooth']>;
  };
  export function useProps(): SmartDevices['model']['props'];
  export function useProps<Value extends any>(
    selector: (props?: SmartDevices['model']['props']) => Value,
    equalityFn?: (a: Value, b: Value) => boolean
  ): Value;
  export function useStructuredProps(): GetStructuredDpState<SmartDeviceProtocols>;
  export function useStructuredProps<Value extends any>(
    selector: (props?: GetStructuredDpState<SmartDeviceProtocols>) => Value,
    equalityFn?: (a: Value, b: Value) => boolean
  ): Value;
  export function useDevice(): SmartDeviceInstanceData;
  export function useDevice<Device extends any>(
    selector: (device: SmartDeviceInstanceData) => Device,
    equalityFn?: (a: Device, b: Device) => boolean
  ): Device;
  export function useActions(): SmartDevices['model']['actions'];
  export function useStructuredActions(): GetStructuredActions<SmartDeviceProtocols>;
}
```

## 使用 SDM

### 根组件使用 SdmProvider

<Callout type="info" emoji="ℹ️">
  该示例文件位于 src/app.tsx，在根组件中使用了 SdmProvider，会等待传入的设备初始化完毕以后再进行渲染子组件，以便后续在任意页面组件中能使用 [SDM 的配套 Hooks](/cn/miniapp/solution-panel/ability/common/sdm/hooks/useProps)
</Callout>

```tsx | pure
import React from 'react';
import 'ray';
import '@/i18n';
import { kit, SdmProvider } from '@ray-js/panel-sdk';
import { devices } from '@/devices';

const { initPanelEnvironment } = kit;

interface Props {
  children: React.ReactNode;
}

initPanelEnvironment({ useDefaultOffline: true });

export default class App extends React.Component<Props> {
  onLaunch() {
    console.info('=== App onLaunch');
  }

  render() {
    return (
      <SdmProvider value={devices.robot}>{this.props.children}</SdmProvider>
    );
  }
}
```

### 通过 SDM 控制设备

<Callout type="info" emoji="ℹ️">
  该示例文件位于 src/pages/home/index.tsx，通过配套的 useActions hooks 来控制智能设备的开关并实时获取开关的值
</Callout>

```jsx | pure
import React from 'react';
import { Button, View } from '@ray-js/ray';
import { useActions, useProps } from '@ray-js/panel-sdk';
import { devices } from '@/devices';

export default function Home() {
  const power = useProps(props => props.power);
  const actions = useActions();
  return (
    <View>
      <Button onClick={() => actions.power.toggle()}>
        点击我切换设备开关状态
      </Button>
      <Text>{`开关状态: ${power}`}</Text>
    </View>
  );
}
```

## 多设备场景

若需在同一小程序内管理多台设备，请使用 **多设备管理** 能力：通过 `SdmProvider` 的 `deviceManager` 注入 `SmartDevicesManager`，并使用多设备 Hooks（`useDevices`、`useDevicesProps`、`useDevicesActions` 等）。详见 [多设备管理 - 使用](/cn/miniapp/solution-panel/ability/common/multi-device/usage) 与 [多设备管理 - Hooks](/cn/miniapp/solution-panel/ability/common/multi-device/hooks/useDevices)。
