Page 2 of 2

Re: SmartAlarmAbility 中告警推送能力无法正常使用

Posted: 2025年 Feb 14日 17:37
by silverlight
xiaoqi 2025年 Feb 14日 17:20

这是一个bug 应该如果你没有初始化的话需要报错提醒的 这个我们后续会修复

好的。但我在\src\composeLayout.tsx中看到了初始化 devices.common.init();具体代码,我展示在上面了,想问一下在这里不算成功初始化了吗?而且我在添加了下方的初始化,依然没能删除和禁用

Code: Select all

// 创建一个 alarm 实例
const Alarm = new SmartAlarmAbility();
 
// 在调用方法之前必须调用 init()
await Alarm.init();

Re: SmartAlarmAbility 中告警推送能力无法正常使用

Posted: 2025年 Feb 18日 14:39
by lshinylee

可以参考下以下 Demo 示例,我们规划会在 2-3 月左右开源 Demo,现阶段可先简单参考下(基于 https://github.com/Tuya-Community/tuya- ... dmTemplate 修改):

  • src/devices/index.ts

    Code: Select all

    import { SmartDeviceSchema } from '@/typings/sdm';
    import {
      SmartAlarmAbility,
      SmartDeviceModel,
      SmartDeviceModelOptions,
      SmartGroupModel,
    } from '@ray-js/panel-sdk';
    import { createDpKit } from '@ray-js/panel-sdk/lib/sdm/interceptors/dp-kit';
    import { getLaunchOptionsSync } from '@ray-js/ray';
    import { protocols } from '@/devices/protocols';
    
    const isGroupDevice = !!getLaunchOptionsSync()?.query?.groupId;
    
    export const dpKit = createDpKit<SmartDeviceSchema>({ protocols });
    
    const options = {
      abilities: [new SmartAlarmAbility()],
      interceptors: dpKit.interceptors,
    } as SmartDeviceModelOptions;
    
    /**
     * SmartDevices 定义来自于 typings/sdm.d.ts,非 TypeScript 开发者可忽略
     * The SmartDevices definition comes from typings/sdm.d.ts and can be ignored by non-TypeScript developers
     */
    export const devices = {
      /**
       * 此处建议以智能设备的名称作为键名赋值
       * It is recommended to assign the name of the smart device as the key name.
       */
      // common: new SmartDeviceModel<SmartDeviceSchema>(options),
      common: isGroupDevice
        ? new SmartGroupModel<SmartDeviceSchema>()
        : new SmartDeviceModel<SmartDeviceSchema, { alarm: SmartAlarmAbility }>(options),
    };
    
  • src/pages/home/index.tsx

    Code: Select all

    import React from 'react';
    import { showToast, View } from '@ray-js/ray';
    import { useCustomAlarm, useDevice } from '@ray-js/panel-sdk';
    import { NavBar, Button, Slider, Switch, CellGroup, Cell } from '@ray-js/smart-ui';
    import styles from './index.module.less';
    
    const Section = ({ title, children }) => {
      return (
        <View className={styles.section}>
          <View className={styles.title}>{title}</View>
          {children}
        </View>
      );
    };
    
    export function Home() {
      const tempCurrentDpId = useDevice(device => device.devInfo.codeIds.temp_current);
      const tempCurrentSchema = useDevice(device => device.dpSchema.temp_current);
      const {
        data,
        loading,
        addCustomAlarm,
        getCustomAlarmList,
        setCustomAlarmStatus,
        deleteCustomAlarm,
      } = useCustomAlarm();
    
      const handleValueChange = React.useCallback(evt => {
        const [start, end] = evt.detail;
        addCustomAlarm({
          name: `${start}~${end}`,
          condition: [
            [tempCurrentDpId, '<', start],
            [tempCurrentDpId, '>=', end],
          ],
        })
          .then(data => {
            console.log('🚀 ~ addCustomAlarm ~ success:', data);
            showToast({ title: '温度上下限告警设置成功', icon: 'none' });
          })
          .catch(err => {
            console.log('🚀 ~ addCustomAlarm ~ failed:', err);
            showToast({ title: '温度上下限告警设置失败', icon: 'error' });
          });
      }, []);
    
      const handleStatusChange = React.useCallback(
        evt => {
          const bindId = data?.[0]?.bindId;
          if (typeof bindId === 'undefined') {
            showToast({ title: '当前不存在可切换状态的告警', icon: 'error' });
            return;
          }
          setCustomAlarmStatus({ bindId, enable: evt.detail })
            .then(data => {
              console.log('🚀 ~ setCustomAlarmStatus ~ success:', data);
              showToast({ title: '温度上下限告警切换状态成功', icon: 'none' });
            })
            .catch(err => {
              console.log('🚀 ~ setCustomAlarmStatus ~ failed:', err);
              showToast({ title: '温度上下限告警切换状态失败', icon: 'error' });
            });
        },
        [data]
      );
    
      const handleDelete = React.useCallback(
        evt => {
          const bindId = data?.[0]?.bindId;
          if (typeof bindId === 'undefined') {
            showToast({ title: '当前不存在可删除的告警', icon: 'error' });
            return;
          }
          deleteCustomAlarm({ bindId })
            .then(data => {
              console.log('🚀 ~ deleteCustomAlarm ~ success:', data);
              showToast({ title: '温度上下限告警删除成功', icon: 'none' });
            })
            .catch(err => {
              console.log('🚀 ~ deleteCustomAlarm ~ failed:', err);
              showToast({ title: '温度上下限告警删除失败', icon: 'error' });
            });
        },
        [data]
      );
    
      React.useEffect(() => {
        getCustomAlarmList();
      }, []);
    
      const conds = data?.[0]?.triggerRuleVO?.conditions;
      const checked = data?.[0]?.triggerRuleVO?.enabled;
      const tempRangeValue = [conds?.[0]?.expr?.[0]?.[2] ?? 0, conds?.[1]?.expr?.[0]?.[2] ?? 10];
    
      return (
        <>
          <NavBar leftText="Home" leftTextType="home" />
          <View className={styles.view}>
            <View className={styles.content}>
              <Section title="查看">
                <CellGroup>
                  {data.map(d => {
                    const name = d?.triggerRuleVO?.name;
                    const conds = d?.triggerRuleVO?.conditions;
                    return (
                      <Cell
                        key={d.bindId}
                        title={name || `bindId: ${d.bindId}`}
                        label={`下限: ${conds?.[0]?.expr?.[0]?.[2]}; 上限: ${conds?.[1]?.expr?.[0]?.[2]}`}
                        // @ts-ignore
                        value={d.enable ? '启用' : '禁用'}
                        isLink={false}
                      />
                    );
                  })}
                </CellGroup>
              </Section>
    
          <Section title="新增/修改">
            <View className={styles['slider-wrapper']}>
              <Slider.RangeSlider
                min={tempCurrentSchema.property.min ?? 0}
                max={tempCurrentSchema.property.max ?? 100}
                barHeight="4px"
                value={tempRangeValue.map(v => +v)}
                inActiveColor="#000000"
                activeColor="#007AFF"
                onChange={handleValueChange}
              />
            </View>
          </Section>
    
          <Section title="启用/禁用">
            <Switch checked={checked} onChange={handleStatusChange} />
          </Section>
    
          <Section title="删除">
            <Button type="danger" onClick={handleDelete}>
              点击删除温度上下限告警
            </Button>
          </Section>
        </View>
      </View>
    </>
      );
    }
    
    export default Home;
    
    • src/pages/home/index.module.less

    Code: Select all

    .view {
      display: flex;
      flex-direction: column;
      align-items: center;
      position: absolute;
      width: 100%;
      height: 100%;
      background-color: #efefef;
    }
    
    .content {
      position: relative;
      display: flex;
      flex-direction: column;
      align-items: center;
      flex: 1;
      width: 100%;
      padding: 32rpx;
    }
    
    .section {
      margin: 16px 0;
      width: 100%;
    }
    
    .title {
      margin-bottom: 12px;
      text-align: left;
      font-size: 38rpx;
      font-weight: 500;
      color: #000;
    }
    
    .slider-wrapper {
      --slider-inactive-background-color: #ffffff;
      width: 300px;
      margin-top: 32px;
    }
    

    实际的执行效果见附件,另外请务必注意以下环境要求:

    • HomeKit 必须要选上并 >=3.0.1 版本
    • 上述 demo 对应的产品品类为 传感/环境/温湿度传感器,且必须存在 temp_current 功能点。(当然该 API 不限制品类,如果要运行该 Demo 则必须满足该要求)