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

理解关系

面板是 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_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 及交互弹窗。

设置页面实现

日志页面

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

日志页面实现