本文档面向已经了解 面板小程序开发 的开发者,您需要充分了解什么是 面板小程序 和 产品功能。若对上述概念有所疑问,涂鸦推荐您了解以下预备知识。如已了解,可跳过本文。

理解关系

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

电工模板使用 SDM(Smart Device Model) 开发,了解 SDM 相关可以参考 SDM 文档。

相关概念

产品名称:通用电工插座

产品介绍

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

需求原型

功能汇总

当前电工插座模板必须具备以下功能点:

switch_1,
countdown_1,

DP 功能

dp 功能

dpid

code

type

mode

property

开关

1

switch_1

布尔型(Bool)

可下发可上报(rw)

倒计时

9

countdown_1

数值型(Value)

可下发可上报(rw)

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

增加电量

17

add_ele

数值型(Value)

可下发可上报(rw)

数值范围: 0-50000, 间距: 100, 倍数: 3, 单位: kwh

当前电流

18

cur_current

数值型(Value)

可下发可上报(rw)

数值范围: 0-80000, 间距: 1, 倍数: 0, 单位: mA

当前功率

19

cur_power

数值型(Value)

只上报(ro)

数值范围: 0-200000, 间距: 1, 倍数: 1, 单位: W

当前电压

20

cur_voltage

数值型(Value)

只上报(ro)

数值范围: 0-5000, 间距: 1, 倍数: 1, 单位: V

以上为实现首页的需求必须具备的功能点,设置页的功能点这里不做介绍。

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

  1. 进入 开发者平台,单击页面左侧 产品 > 产品开发,在 产品开发 页面单击 创建产品。
  2. 在 标准类目 下选择 电工,产品品类选择 插座。
  3. 选择智能化方式和产品方案,并完善产品信息,如在 产品名称 处填写 Public Socket。
  4. 单击 创建产品 按钮,完成产品创建。
  5. 产品创建完成后,进入到 添加标准功能 页面,保持默认选择的标准功能即可,然后单击 确定。
  6. 在 高级功能 区域,可以根据产品功能需求开启或者关闭高级特色功能,这里需要开启 电量统计基础版。

🎉 完成以上步骤后,一个名为 PublicSocket 的电工插座产品创建完成。

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

面板小程序的开发在 小程序开发者 平台上进行操作,首先请前往 小程序开发者平台 完成平台的注册登录。

订阅统计及日志云能力

在开发者平台,选择创建好的面板小程序,进入 小程序管理 页面,单击 开发设置 进入 开发设置 页面。在云能力模块中,找到 小程序设备日志能力 及 小程序图表能力,然后单击 订阅资源包 来订阅。

创建 IDE 项目

  1. 打开 IDE,单击 新建,输入项目名称,关联创建的面板小程序,在 关联产品 处选择 测试单插,然后单击 下一步。
  2. 在 选择模板 页面,选择 电工单插件高级模板,单击 创建 完成项目的创建。
  3. 回到项目管理列表,选择刚创建好的项目,进入项目后,即可进行预览并开发。

工程目录

完成以上步骤后,一个面板小程序的开发模初始化完成。以下为工程目录的介绍:

├── 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 #智能设备类型定义文件

需求实现

IDE 生成 SDM schema 到项目

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

export const defaultSchema = [
  {
    attr: 1024,
    canTrigger: true,
    code: 'switch_1',
    defaultRecommend: false,
    editPermission: true,
    executable: true,
    extContent: '',
    iconname: 'icon-dp_power2',
    id: 1,
    mode: 'rw',
    name: '开关1',
    property: {
      type: 'bool',
    },
    type: 'obj',
  },
  {
    attr: 1120,
    canTrigger: false,
    code: 'countdown_1',
    defaultRecommend: false,
    editPermission: true,
    executable: false,
    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',
  },
  {
    attr: 1120,
    canTrigger: false,
    code: 'add_ele',
    defaultRecommend: false,
    editPermission: true,
    executable: false,
    extContent: '{"trigger":"direct"}',
    iconname: 'icon-battery',
    id: 17,
    mode: 'rw',
    name: '增加电量',
    property: {
      unit: 'kwh',
      min: 0,
      max: 50000,
      scale: 3,
      step: 100,
      type: 'value',
    },
    type: 'obj',
  },
  {
    attr: 1088,
    canTrigger: true,
    code: 'cur_current',
    defaultRecommend: false,
    editPermission: true,
    executable: false,
    extContent: '',
    iconname: 'icon-Ele',
    id: 18,
    mode: 'ro',
    name: '当前电流',
    property: {
      unit: 'mA',
      min: 0,
      max: 80000,
      scale: 0,
      step: 1,
      type: 'value',
    },
    type: 'obj',
  },
  {
    attr: 1088,
    canTrigger: true,
    code: 'cur_power',
    defaultRecommend: false,
    editPermission: true,
    executable: false,
    extContent: '',
    iconname: 'icon-dp_tool',
    id: 19,
    mode: 'ro',
    name: '当前功率',
    property: {
      unit: 'W',
      min: 0,
      max: 200000,
      scale: 1,
      step: 1,
      type: 'value',
    },
    type: 'obj',
  },
  {
    attr: 1088,
    canTrigger: true,
    code: 'cur_voltage',
    defaultRecommend: false,
    editPermission: true,
    executable: false,
    extContent: '',
    iconname: 'icon-a_function_turbo',
    id: 20,
    mode: 'ro',
    name: '当前电压',
    property: {
      unit: 'V',
      min: 0,
      max: 5000,
      scale: 1,
      step: 1,
      type: 'value',
    },
    type: 'obj',
  },
];

需求:单击位于首页中间的按钮来切换 switch_1 开关状态

  1. 首先分析需求:
    • 首页添加组件 开关按钮:
      1. 根据 switch_1 下发的值展示不同按钮图片。
      2. 单击 开关 组件触发事件,上报 开、关 的 DP 值。
    • 确认开关 DP 为 switch_1,可作为属性传入组件。
    • 使用 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>
        );
      }
      
    • 使用 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>
        );
      }
      
  2. 根据上述分析,我们来实现开关组件。
    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>
      );
    });
    
    
  3. 引入代码之后,首页有了一个可操控的按钮,这时可以设置 IDE 右侧 控制面板 > 1.开关 的值为 false/true 进行虚拟面板 dp 点的下发/上报。也可以单击刚刚完成的组件,查看 IDE 控制面板的状态来验证产品功能。

首页倒计时提示

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

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

倒计时提示组件实现

首页倒计时弹窗

单击首页底部 倒计时 弹出倒计时提示来设置倒计时。若未设置过倒计时则展示该组件,若已设置则可操作关闭倒计时。

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

倒计时弹窗组件实现

电量统计页面

单击首页底部 统计 进入 电量统计 页面,可以显示当前电流、当前电压、当前功率的数据,并获取统计数据。

获取统计相关接口可参考 统计。

统计页面实现

设置页面

单击首页底部 设置 进入 设置 页面,对除 switch_1、countdown_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 及交互弹窗。

设置页面实现

日志页面

在设备页面单击 开关日志 进入 日志 页面。 这里使用了 获取上报记录的 API。

日志页面实现