本文档面向已经了解 面板小程序开发 的开发者,你需要充分的了解什么是面板小程序 产品功能 若您对上述概念有所疑问,我们推荐你去看一些预备知识。如果您已了解,可跳过本文。

理解关系

面板作为 IoT 智能设备在 App 终端上的产品形态,创建产品之前,首先来了解一下什么是面板,以及和产品、设备之间的关系。

  1. 面板 是运行在 智能生活 AppOEM App(涂鸦定制 App) 上的界面交互程序,用于控制 智能设备 的运行,展示 智能设备 实时状态。
  2. 产品面板智能设备 联系起来,产品描述了其具备的功能、在 App 上面板显示的名称、智能设备拥有的功能点等。
  3. 智能设备 是搭载了 涂鸦智能模组 的设备,通常在设备上都会贴有一张二维码,使用 智能生活 App 扫描二维码,即可在 App 中获取并安装该设备的控制 面板
  4. 产品面板设备 之间的关系可参考下图。

电工模板使用 SDM(Smart Device Model) 开发,关于 SDM 相关可以 查看 SDM 文档

相关概念

产品名称:通用电工插座

产品介绍

提供插座的打开与关闭的基本功能,并提供关闭倒计时、增加电量、更新当前电流、功率参数等功能,根据以下通用电工的开发教程帮助您开发面板小程序去控制插座。

需求原型

  1. 首页 点击中间按钮切换 switch_1 开关状态。
  2. 首页 页面展示倒计时提示,根据开关状态、手机系统的 24 小时制或 12 小时制、countdown_1 的值来显示对应的提示文案,若未设置倒计时则不展示。
  3. 点击首页底部倒计时 弹出倒计时提示框组件来设置倒计时,若未设置则展示设置倒计时的组件,若已设置则可关闭倒计时。
  4. 点击首页底部设置进入设置页面,可以对除 switch_1countdown_1 的所有 可下发可上报(rw)功能进行设置。

功能汇总

当前电工插座模板必须的功能点:

switch_1,
countdown_1,

开关

参数

取值

dpid

1

code

switch_1

type

布尔型(Bool)

mode

可下发可上报(rw)

开关 1 倒计时

参数

取值

dpid

9

code

countdown_1

type

数值型(Value)

mode

可下发可上报(rw)

property

数值范围: 0-86400, 间距: 1, 倍数: 0, 单位: s

上面为首页需求必须的功能点,设置页功能点这里不做介绍。

首先需要创建一个电工类产品,定义产品有哪些功能点,然后面板中再根据这些功能点一一实现。

进入IoT 平台,点击左侧产品菜单,产品开发,创建产品,选择标准类目 -> 电工 -> 插座:

选择功能点,这里我们只需要默认的标准功能即可。

🎉 在这一步,我们创建了一个名为 PublicSocket的电工插座产品。

开发者平台创建面板小程序

这部分我们在 小程序开发者 平台上进行操作,注册登录 小程序开发者平台

创建 IDE 项目

打开 IDE,选择新建,输入项目名称,关联创建的面板小程序,选择单插产品,然后点击下一步

在下一步中,找到电工单插模板,并完成创建项目

此时,回到项目管理列表,选择刚创建好的项目,进入后,即可进行预览并开发。

工程目录

上面的步骤我们已经初始化好了一个面板小程序的开发模板,下面我们介绍下工程目录。

├── src
│ ├── app.config.ts # 自动生成配置
│ ├── app.tsx # App 根组件
│ ├── components # 组件目录
│ ├── constant # 常量目录
│ ├── devices # 智能设备模型目录
│ │ ├── index.ts # 定义并导出智能设备模型
│ │ └── schema.ts # 当前智能设备 DP 功能点描述,IDE 可自动生成
│ ├── global.config.ts
│ ├── hooks # 自定义 hooks 目录
│ ├── i18n # 多语言目录
│ ├── pages # 页面目录
│ └── routes.config.ts # 路由配置
│─── typings #业务类型定义目录
│ └── sdm.d.ts #智能设备类型定义文件

需求实现

1. IDE 生成 SDM schema到项目。

生成 SDM schema 至项目中,可以查看 src/devices/schema.ts

export const defaultSchema = [
  {
    attr: 128,
    canTrigger: true,
    code: 'switch_1',
    defaultRecommend: false,
    editPermission: false,
    executable: true,
    extContent: '',
    iconname: 'icon-dp_power2',
    id: 1,
    mode: 'rw',
    name: '开关1',
    property: {
      type: 'bool',
    },
    type: 'obj',
  },
  {
    attr: 640,
    canTrigger: true,
    code: 'countdown_1',
    defaultRecommend: true,
    editPermission: false,
    executable: true,
    extContent: '',
    iconname: 'icon-dp_time2',
    id: 9,
    mode: 'rw',
    name: '开关1倒计时',
    property: {
      unit: 's',
      min: 0,
      max: 86400,
      scale: 0,
      step: 1,
      type: 'value',
    },
    type: 'obj',
  },
  // ...
];

2. 需求 -首页 点击中间按钮切换 switch_1 开关状态

分析需求:

  1. 首页添加组件 开关按钮
    1. 根据 switch_1 下发的值展示不同按钮图片。
    2. 点击开关组件触发事件,上报「开」「关」的 dp 值。
  2. 确认开关 dp 为switch_1,可作为属性传入组件。
  3. 使用 useProps 获取实时下发的 dp 值。示例:
    import React from 'react';
    import { View } from '@ray-js/ray';
    import { useProps } from '@ray-js/sdm-react';
    
    export default function () {
      const switch_1 = useProps((dpState) => dpState.switch_1);
      return (
        <View style={{ flex: 1 }}>
          <View>switch_1: {switch_1}</View>
        </View>
      );
    }
    
  4. 使用 useActions 获取dp上报的行为示例:
    import React from 'react';
    import { View } from '@ray-js/ray';
    import { useActions } from '@ray-js/sdm-react';
    
    export default function () {
      const actions = useActions();
      return (
        <View style={{ flex: 1 }}>
          <Button
            onClick={() => {
              actions.switch_1.set(false);
            }}
          >
            change action
          </Button>
        </View>
      );
    }
    

根据上述分析,我们来实现开关组件。

import React from 'react';
import clsx from 'clsx';
import { View } from '@ray-js/ray';
import { DpBooleanAction } from '@tuya-miniapp/sdm';
import { useProps, useActions } from '@ray-js/sdm-react';
import { Icon } from '@/components/icon';
import { icons } from '@/res';
import styles from './index.module.less';

export interface Props {
  dpCode: string;
}

export const PowerButton = React.memo<Props>(props => {
  const { dpCode } = props;
  const value = useProps(dpState => dpState[dpCode]);

  const actions = useActions();

  if (!dpCode || typeof value !== 'boolean') {
    return null;
  }

  const action = actions[dpCode] as DpBooleanAction;

  return (
    <View className={styles['power-button']} onClick={action.toggle}>
      <View
        className={clsx(styles['power-button-content'], {
          [`${styles['power-button-off']}`]: !value,
        })}
      />
      <Icon
        className={styles['power-button-icon']}
        d={icons.power}
        size="34px"
        fill={value ? '#ef550d' : '#ffffff'}
      />
    </View>
  );
});

开关组件实现

我们实现了 PowerButton 组件,下面的代码就可以在首页引入,并传入开关的 dp code,下面修改首页的代码。

import React from 'react';
import { setNavigationBarTitle, View } from '@ray-js/ray';
import { useDevice } from '@ray-js/sdm-react';
import { PowerButton } from '@/components';
import styles from './index.module.less';

export default function Home() {
  const deviceName = useDevice((d) => d.devInfo.name);

  React.useEffect(() => {
    setNavigationBarTitle({ title: deviceName });
  }, [deviceName]);

  return (
    <View className={styles.view}>
      <View className={styles.content}>
        <View className={styles['space-between']}>
          <PowerButton dpCode="switch_1" />
        </View>
      </View>
    </View>
  );
}

引入了代码之后,我们的首页有了一个可操控的按钮,这时我们可以修改 IDE右侧控制面板 -> 1.开关 -> false/true 进行虚拟面板dp点的下发与上报,也可以点击我们刚刚完成的组件,查看IDE 控制面板的状态来验证我们的产品功能。

1. 首页 页面展示倒计时提示,根据开关状态、手机系统的 24 小时制或 12 小时制、countdown_1 的值来显示对应的提示文案,若未设置倒计时则不展示。

  1. 创建倒计时提示组件,根据 开关状态 switch_1 及倒计时 countdown_1 状态下发的值来控制展示内容。

倒计时提示组件实现

2. 点击首页底部倒计时 弹出倒计时提示来设置倒计时,若未设置则展示设置倒计时的组件,若已设置则可关闭倒计时。

  1. 创建底部 Tab 组件及倒计时弹窗组件,根据 倒计时 countdown_1 状态下发的值来控制展示内容。
  2. 通过 useActions 上报 倒计时 countdown_1的状态。

倒计时弹窗组件实现

3. 点击首页底部设置进入设置页面,可以对除 switch_1countdown_1 的所有 可下发可上报(rw)功能进行设置。

  1. 设置页面展示所有 可下发可上报(rw)的功能并进行设置。
  2. 通过 useDevice 获取全部 功能点 dp
    import { useDevice } from '@ray-js/sdm-react';
    const { devInfo } = useDevice();
    // 获取到全部 dp schema
    const dpSchemas = devInfo.schema;
    
  3. 根据不同功能点 dp的类型进行展示不同 UI 及交互弹窗。

设置页面实现