[English](./README.md) | 简体中文

# @ray-js/lamp-schedule-core

[![latest](https://img.shields.io/npm/v/@ray-js/lamp-schedule-core/latest.svg)](https://www.npmjs.com/package/@ray-js/lamp-schedule-core) [![download](https://img.shields.io/npm/dt/@ray-js/lamp-schedule-core.svg)](https://www.npmjs.com/package/@ray-js/lamp-schedule-core)

> 照明计划模块核心能力

## 安装

```sh
$ npm install @ray-js/lamp-schedule-core
// 或者
$ yarn add @ray-js/lamp-schedule-core
```

## 开发

```sh
# 实时编译Demo代码
yarn start:tuya
```

## API

### useScheduleInit

- 初始化计划模块能力
  - 初始化哪些内容？
    - SmartStorageAbility
    - getDeviceInfo

```tsx
// 初始化计划模块能力，由于是异步获取，所以需要等待isReady为true后再使用
const { isReady } = useScheduleInit({
  devId: deviceId,
  groupId,
});

if (!isReady) {
  return null;
}
// 其他代码
```

### scheduleDpCodes

- 计划模块标准 dpCode

### dp 值获取与更新

#### useBaseLightDp

- 获取计划模块 dpCode 对应的 dpValue，不做 dp 值转换获取的是原始 dp 值

```tsx
import { useBaseLightDp } from '@ray-js/lamp-schedule-core';
const { dpValue: power } = useBaseLightDp(scheduleDpCodes.SWITCH_LED);
```

#### 获取具体模块 dp 值

```tsx
// 以生物节律为例, 其他类似
import { useRhythmsDp } from '@ray-js/lamp-schedule-core';
const { dpValue: rhythmDpValue, updateDp: updateRhythmDpValue } = useRhythmsDp();
```

### 常规定时

#### TimerContextProvider

- 定时上下文， 方便后续使用 useTimerContext 获取定时数据

```tsx
import { TimerContextProvider } from '@ray-js/lamp-schedule-core';

<TimerContextProvider>
  {/* 定时列表模块 */}
  <CommonTimerList />
</TimerContextProvider>;
```

#### 定时列表

```tsx
import { useTimerListFlush, TTimerData, useTimerList } from '@ray-js/lamp-schedule-core';

const { flushTimerList } = useTimerListFlush();
const { getTimerList } = useTimerList();

getTimerList()
  .then((res: { timers?: TTimerData[] }) => {
    const { timers } = res;
    flushTimerList(timers);
    // 云定时返回值
    if (timers) {
      scheduleLogger.debug('getTimerList success:', res);
    }
  })
  .catch(err => {
    scheduleLogger.error('getTimerList fail:', err);
  });
```

#### useTimerContext

```tsx
const { state } = useTimerContext();
// 云定时列表、rtc 定时列表
const { cloudTimerList = [], rtcTimerList = [] } = state;
```

#### useTimerUpdateStatusWithFlush

- 更新定时开关状态

```tsx
const { updateStatusTimerWithFlush, TTimerData } = useTimerUpdateStatusWithFlush();

// 定时数据
const detail: TTimerData = xxx;

updateStatusTimerWithFlush(detail.timerId, !detail.status)
  .then(() => {
    hideLoading();
  })
  .catch(err => {
    scheduleLogger.error('handleSwitch, updateTimerWithFlush:', err);
  });
```

#### 增加定时

```tsx
const { useTimerAddWithFlush } = useTimerRemoveWithFlush();

const { addTimerWithFlush } = useTimerAddWithFlush();

const category = 'timer'; // 含义详见：[请求参数](https://developer.tuya.com/cn/miniapp/develop/ray/api/timer/base/addTimer#%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0)
const _timer: TTimerDataAdd = {};

// 冲突判断
const conflict = Conflict.add({
  type: EScheduleFunctionType.TIMER,
  detail: [_timer as TTimerDataUpdate],
});

if (conflict.isConflict) {
  // 存在冲突，进行提示等处理
  return;
}
// 增加定时
addTimerWithFlush(_timer, category)
  .then((newTimer: TTimerData) => {
    hideLoading();
  })
  .catch(err => {
    scheduleLogger.error('addTimerWithFlush err:', err);
  });
```

#### 删除定时

```tsx
const { removeTimerWithFlush } = useTimerRemoveWithFlush();

removeTimerWithFlush(timerId)
  .then(() => {
    showToast({
      title: Strings.getLang('delete_success'),
      icon: 'success',
    });
    resolve(true);
  })
  .catch(err => {
    scheduleLogger.error('removeTimerWithFlush timer failed: ', err);
    resolve(false);
  });
```

#### 编辑定时

```tsx
import { useTimerUpdateWithFlush } from '@ray-js/lamp-schedule-core';

const { updateTimerWithFlush } = useTimerUpdateWithFlush();

const newTimerData: TTimerDataUpdate = {};
const oldTimerData: TTimerDataUpdate = {};

updateTimerWithFlush(newTimerData, oldTimerData)
  .then(() => {
    onClose && onClose();
  })
  .catch(err => {
    hideLoading();
    scheduleLogger.error('handleUpdateTimer, updateTimerWithFlush:', err);
  });
```

### 循环定时

- 获取与更新 dp 值

```tsx
const { dpValue: cycleDataDpValue, updateDp: updateCycleDpValue } = useCycleDp();
```

### 随机定时

- 获取与更新 dp 值

```tsx
const { dpValue: randomDataDpValue, updateDp: updateRandomDpValue } = useRandomDp();
```

### 入睡定时

- 获取与更新 dp 值

```tsx
const { dpValue: sleepDataDpValue, updateDp: updateSleepDpValue } = useSleepDp();
```

### 唤醒定时

- 获取与更新 dp 值

```tsx
const { dpValue: wakeDataDpValue, updateDp: updateWakeDpValue } = useWakeUpDp();
```

### 倒计时

#### useCountdownDp

- 获取倒计时 dp 值，并支持更新 dp

```tsx
import { useCountdownDp } from '@ray-js/lamp-schedule-core';
const { dpValue: countdownDpValue, updateDp: updateCountdownDpValue } = useCountdownDp();
```

#### useCountdownDpPull

- 主动拉取倒计时 dp 数据, 一般用于 sigmesh 设备

```tsx
useCountdownDpPull();
```

## 冲突判断

用来按断当前设置的计划与之前设置的计划是否有冲突

```tsx
import { Conflict } from '@ray-js/lamp-schedule-core';
```

### 初始化： init

```tsx
import { Conflict } from '@ray-js/lamp-schedule-core';
// 由于模块可能比较分散，所以可多次执行 init，会进行叠加并去重
Conflict.init([
  {
    // 冲突类型
    type: EScheduleFunctionType.RHYTHM,
    // 冲突的dp值,这里以生物节律 dp 为例子
    detail: [
      {
        ...rhythmDpValue,
        weeks,
        status: rhythmDpValue?.power,
      },
    ],
  },
]);
```

### 添加：add

```tsx
const { isConflict, conflictList } = Conflict.add({
  // 冲突类型
  type: EScheduleFunctionType.COUNTDOWN,
  // 冲突的dp值,这里以倒计时 dp 为例子
  detail: [
    {
      countdown: _countdownValue,
      status: !!_countdownValue,
    },
  ],
});

if (isConflict) {
  // 存在冲突，进行提示等处理
  return;
}
// 其他代码
```

### 更新：update

```tsx
const { isConflict, conflictList = [] } = Conflict.update(
  {
    // 冲突类型
    type: EScheduleFunctionType.TIMER,
    detail: [_newTimer],
  },
  {
    // 冲突类型
    type: EScheduleFunctionType.TIMER,
    detail: [timer],
  }
);
if (isConflict) {
  // 存在冲突，进行提示等处理
  return;
}
```

### 删除：remove

```tsx
// 当删除计划内模块时，需要将对应模块的冲突数据删除
Conflict.remove({
  // 冲突类型
  type: EScheduleFunctionType.TIMER,
  detail: [item as TTimerData],
});
```

## 支持能力

### 初始化

```tsx
// 方法1:
import { Support } from '@ray-js/lamp-schedule-core/lib/utils/ScheduleSupport';
const support = new Support({ devId: devInfo.devId });

// 方法2:

import { useSupport } from '@ray-js/lamp-schedule-core';

const support = useSupport();
```

### isSupportDp

```tsx
// 更具 dpCode 判断是否支持倒计时
const isSupportCountdown = support.isSupportDp(scheduleDpCodes.COUNTDOWN);
```

### isGroupDevice

```tsx
// 判断是否是群组设备
const isGroup = support.isGroupDevice();
```

### isSigMeshDevice

```tsx
// 判断是否是 sigmesh 设备
const isSigMesh = support.isSigMeshDevice();
```

### getDevInfo

```tsx
// 获取设备信息
const devInfo = support.getDevInfo();
```

### useSupportCloudTimer: 判断是否支持云定时

```tsx
const isSupportCloudTimer = useSupportCloudTimer();
```

### useSupportRtcTimer: 判断是否支持 rtc 定时

```tsx
const isSupportLocalTimer = useSupportLocalTimer();
```

## dp 解析

### getCycleParser 循环定时 dp 解析函数

```ts
const cycleParser = getCycleParser();

// 解析
cycleParser.parser();
// 反解析
cycleParser.formatter();
```

### getRandomParser 随机定时 dp 解析函数

```ts
const randomParser = getRandomParser();

// 解析
randomParser.parser();
// 反解析
randomParser.formatter();
```

### getSleepParser 入睡定时 dp 解析函数

```ts
const sleepParser = getSleepParser();

// 解析
sleepParser.parser();
// 反解析
sleepParser.formatter();
```

### getWakeupParser 唤醒定时 dp 解析函数

```ts
const wakeupParser = getWakeUpParser();

// 解析
wakeupParser.parser();
// 反解析
wakeupParser.formatter();
```

### getRhythmParser 生物节律定时 dp 解析函数

```ts
const rhythmsParser = getRhythmParser();

// 解析
rhythmsParser.parser();
// 反解析
rhythmsParser.formatter();
```

### getRtcParser 本地定时 dp 解析函数

```ts
const rtcParser = getRtcParser();

// 解析
rtcParser.parser();
// 反解析
rtcParser.formatter();
```

## 其他能力

```tsx
import { useHourType, getSupportIns } from '@ray-js/lamp-schedule-core';
// 是否 12 小时制
const { is12Hour } = useHourType();
// 获取 Support 实例, 用在非函数式组件中
const support = getSupportIns();
```

## 具体用法

### 1. 初始化计划模块能力

```tsx
import { useScheduleInit } from '@ray-js/lamp-schedule-core';
const { isReady } = useScheduleInit({
  devId: deviceId,
  groupId,
});
if (!isReady) {
  return null;
}
```

### 2. 选择要开发的能力

```tsx
// 入睡模块为例
import { useSleepDp, TSleepData } from '@ray-js/lamp-schedule-core';

// 2.0 判断是否支持入睡模块
const support = useSupport();
// 判断是否支持入睡 dp
const isSupportSleep = support.isSupportDp(scheduleDpCodes.SLEEP);
if (!isSupportSleep) {
  // 不支持直接返回或页面中不展示
  return null;
}

// 2.1 获取 dp 值
const { dpValue: sleepDpValue, updateDp: updateSleepDpValue } = useSleepDp<TSleepData>();

// 获取到入睡 dp 数据，具体格式查看 TSleepData
// 2.2 添加入睡 dp 数据
// 2.2.1 保存时先判断是否有冲突
// sleepDpValue 为 TSleepData 类型
const restDp = {}; // 修改的入睡值
const newNode: TSleepData = {
  ...sleepDpValue,
  ...restDp,
  status: true,
};
const { isConflict, conflictList = [] } = Conflict.add({
  // 冲突类型
  type: EScheduleFunctionType.SLEEP,
  // 冲突的dp值,这里以入睡 dp 为例子
  detail: [newNode],
});
if (isConflict) {
  // 存在冲突，进行提示等处理
  return;
}
// 2.2.2 从 useSleepDp（会自动刷新值）获取到新的 sleepDpValue 进行页面展示刷新

// 2.3 编辑更新入睡 dp 数据
// 2.3.1 保存时先判断是否有冲突
// sleepDpValue 为 TSleepData 类型
const restDp = {}; // 修改的入睡值
const newNode: TSleepData = {
  ...sleepDpValue,
  ...restDp,
  status: true,
};

const { isConflict, conflictList = [] } = Conflict.update(
  {
    type: EScheduleFunctionType.SLEEP,
    // 新的节点
    detail: [newNode],
  },
  {
    type: EScheduleFunctionType.SLEEP,
    // 当前编辑的节点
    detail: [sleepDataDpValue.nodes?.[sleepData?.index]],
  }
);
if (isConflict) {
  // 存在冲突，进行提示等处理
  return;
}
// 2.3.2 从 useSleepDp（会自动刷新值）获取到新的 sleepDpValue 进行页面展示刷新

// 2.4 删除入睡 dp 数据
// 2.4.1 保存时先将数据移除
const index = xx; // 选中的被删除节点索引
const currentNode = sleepDataDpValue?.nodes?.[index];
if (currentNode) {
  Conflict.remove({
    type: EScheduleFunctionType.SLEEP,
    detail: [currentNode],
  });
}
// 2.4.2 删除成功后， useSleepDp（会自动刷新值）获取到新的 sleepDpValue 进行页面展示刷新

// 以上用“入睡模块”为例，展示了模块功能的增删改查能力，其它模块用法类似
```