English | [简体中文](./README-zh_CN.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)

> 照明计划模块核心能力

## Installation

```sh
$ npm install @ray-js/lamp-schedule-core
# or
$ yarn add @ray-js/lamp-schedule-core
```

Here's the English translation of the provided API documentation:

---

## API

### useScheduleInit

- Initializes the scheduling module.

```tsx
// Initializes the scheduling module. Since it's an asynchronous operation,
// wait for `isReady` to be true before using it.
const { isReady } = useScheduleInit({
  devId: deviceId,
  groupId,
});

if (!isReady) {
  return null;
}
// Other code
```

### scheduleDpCodes

- Standard DP codes for the scheduling module.

### DP Value Retrieval and Update

#### useBaseLightDp

- Retrieves the DP value corresponding to a scheduling module DP code. This returns the raw DP value without conversion.

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

#### Obtain the specific module dp value

```tsx
// biological rhythm example, Others similar
import { useRhythmsDp } from '@ray-js/lamp-schedule-core';
const { dpValue: rhythmDpValue, updateDp: updateRhythmDpValue } = useRhythmsDp();
```

### Regular Timer

#### TimerContextProvider

- Timer context provider, making it easy to retrieve timer data later using `useTimerContext`.

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

<TimerContextProvider>
  {/* Timer list module */}
  <CommonTimerList />
</TimerContextProvider>;
```

#### Timer List

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

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

const cloudCategory = ''; // Cloud timing category value, default is timer, for details, see: [Request Parameters](https://developer.tuya.com/cn/miniapp/develop/ray/api/timer/base/addTimer#%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0)
getTimerList()
  .then((res: { timers?: TTimerData[] }) => {
    const { timers } = res;
    flushTimerList(timers);
    // Cloud timer return value
    if (timers) {
      scheduleLogger.debug('getTimerList success:', res);
    }
  })
  .catch(err => {
    scheduleLogger.error('getTimerList fail:', err);
  });
```

#### useTimerContext

```tsx
const { state } = useTimerContext();
// Cloud timer list, RTC timer list
const { cloudTimerList = [], rtcTimerList = [] } = state;
```

#### useTimerUpdateStatusWithFlush

- Updates the timer's on/off status.

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

// Timer data
const detail: TTimerData = xxx;

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

#### Add Timer

```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 = {};

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

if (conflict.isConflict) {
  // There's a conflict, handle with a prompt, etc.
  return;
}
// Add timer
addTimerWithFlush(_timer, category)
  .then((newTimer: TTimerData) => {
    hideLoading();
  })
  .catch(err => {
    scheduleLogger.error('addTimerWithFlush err:', err);
  });
```

#### Delete Timer

```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);
  });
```

#### Edit Timer

```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);
  });
```

### Cycle Timer

- Retrieve and update DP values.

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

### Random Timer

- Retrieve and update DP values.

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

### Sleep Timer

- Retrieve and update DP values.

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

### Wake-Up Timer

- Retrieve and update DP values.

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

### Countdown

#### useCountdownDp

- Retrieves countdown DP values and supports DP updates.

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

#### useCountdownDpPull

- Actively pulls countdown DP data, typically used for Sigmesh devices.

```tsx
useCountdownDpPull();
```

---

## Conflict Detection: Used to determine if the currently set schedule conflicts with previously set schedules.

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

### Initialization: init

```tsx
import { Conflict } from '@ray-js/lamp-schedule-core';
// Since modules might be scattered, init can be executed multiple times.
// It will accumulate and deduplicate entries.
Conflict.init([
  {
    // Conflict type
    type: EScheduleFunctionType.RHYTHM,
    // Conflicting DP value, here taking biological rhythm DP as an example
    detail: [
      {
        ...rhythmDpValue,
        weeks,
        status: rhythmDpValue?.power,
      },
    ],
  },
]);
```

### Add: add

```tsx
const { isConflict, conflictList } = Conflict.add({
  // Conflict type
  type: EScheduleFunctionType.COUNTDOWN,
  // Conflicting DP value, here taking countdown DP as an example
  detail: [
    {
      countdown: _countdownValue,
      status: !!_countdownValue,
    },
  ],
});

if (isConflict) {
  // There's a conflict, handle with a prompt, etc.
  return;
}
// Other code
```

### Update: update

```tsx
const { isConflict, conflictList = [] } = Conflict.update(
  {
    // Conflict type
    type: EScheduleFunctionType.TIMER,
    detail: [_newTimer],
  },
  {
    // Conflict type
    type: EScheduleFunctionType.TIMER,
    detail: [timer],
  }
);
if (isConflict) {
  // There's a conflict, handle with a prompt, etc.
  return;
}
```

### Remove: remove

```tsx
// When deleting a module within a schedule, the corresponding module's conflict data needs to be removed.
Conflict.remove({
  // Conflict type
  type: EScheduleFunctionType.TIMER,
  detail: [item as TTimerData],
});
```

---

## Supported Capabilities

### Initialization

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

// Method 2:

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

const support = useSupport();
```

### isSupportDp

```tsx
// Determine if countdown is supported based on the dpCode.
const isSupportCountdown = support.isSupportDp(scheduleDpCodes.COUNTDOWN);
```

### isGroupDevice

```tsx
// Determine if it's a group device.
const isGroup = support.isGroupDevice();
```

### isSigMeshDevice

```tsx
// Determine if it's a Sigmesh device.
const isSigMesh = support.isSigMeshDevice();
```

### getDevInfo

```tsx
// Get device information.
const devInfo = support.getDevInfo();
```

### useSupportCloudTimer: Determine if cloud timers are supported.

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

### useSupportRtcTimer: Determine if RTC timers are supported.

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

### Other Capabilities

```tsx
import { useHourType, getSupportIns } from '@ray-js/lamp-schedule-core';
// Whether it's 12-hour format.
const { is12Hour } = useHourType();
// Get Support instance, for use in non-functional components.
const support = getSupportIns();
```

## DP Parsers

### getCycleParser - Periodic Timer DP Parser Function

```ts
const cycleParser = getCycleParser();

// Parse
cycleParser.parser();
// Unparse
cycleParser.formatter();
```

### getRandomParser - Random Timer DP Parser Function

```ts
const randomParser = getRandomParser();

// Parse
randomParser.parser();
// Unparse
randomParser.formatter();
```

### getSleepParser - Sleep Timer DP Parser Function

```ts
const sleepParser = getSleepParser();

// Parse
sleepParser.parser();
// Unparse
sleepParser.formatter();
```

### getWakeupParser - Wake-up Timer DP Parser Function

```ts
const wakeupParser = getWakeUpParser();

// Parse
wakeupParser.parser();
// Unparse
wakeupParser.formatter();
```

### getRhythmParser - Biological Rhythm Timer DP Parser Function

```ts
const rhythmsParser = getRhythmParser();

// Parse
rhythmsParser.parser();
// Unparse
rhythmsParser.formatter();
```

### getRtcParser - Local Timer DP Parser Function

```ts
const rtcParser = getRtcParser();

// Parse
rtcParser.parser();
// Unparse
rtcParser.formatter();
```

## Specific Usage

### 1. Initializing Schedule Module Capabilities

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

### 2\. Selecting the Capability to Develop

```tsx
// Taking the sleep module as an example
import { useSleepDp, TSleepData } from '@ray-js/lamp-schedule-core';

// 2.0 Check if the sleep module is supported
const support = useSupport();
// Check if the sleep DP (data point) is supported
const isSupportSleep = support.isSupportDp(scheduleDpCodes.SLEEP);
if (!isSupportSleep) {
  // If not supported, return directly or don't display on the page
  return null;
}

// 2.1 Get the DP value
const { dpValue: sleepDpValue, updateDp: updateSleepDpValue } = useSleepDp<TSleepData>();

// The sleep DP data is obtained; refer to TSleepData for the specific format.
// 2.2 Add sleep DP data
// 2.2.1 Before saving, check for conflicts
// sleepDpValue is of type TSleepData
const restDp = {}; // Modified sleep value
const newNode: TSleepData = {
  ...sleepDpValue,
  ...restDp,
  status: true,
};
const { isConflict, conflictList = [] } = Conflict.add({
  // Conflict type
  type: EScheduleFunctionType.SLEEP,
  // Conflict DP value; here, the sleep DP is used as an example
  detail: [newNode],
});
if (isConflict) {
  // If there's a conflict, prompt for resolution
  return;
}
// 2.2.2 Get the new sleepDpValue from useSleepDp (which automatically refreshes the value) to refresh the page display.

// 2.3 Edit and update sleep DP data
// 2.3.1 Before saving, check for conflicts
// sleepDpValue is of type TSleepData
const restDp = {}; // Modified sleep value
const newNode: TSleepData = {
  ...sleepDpValue,
  ...restDp,
  status: true,
};

const { isConflict, conflictList = [] } = Conflict.update(
  {
    type: EScheduleFunctionType.SLEEP,
    // New node
    detail: [newNode],
  },
  {
    type: EScheduleFunctionType.SLEEP,
    // Currently edited node
    detail: [sleepDataDpValue.nodes?.[sleepData?.index]],
  }
);
if (isConflict) {
  // If there's a conflict, prompt for resolution
  return;
}
// 2.3.2 Get the new sleepDpValue from useSleepDp (which automatically refreshes the value) to refresh the page display.

// 2.4 Delete sleep DP data
// 2.4.1 When saving, first remove the data
const index = xx; // Index of the selected node to be deleted
const currentNode = sleepDataDpValue?.nodes?.[index];
if (currentNode) {
  Conflict.remove({
    type: EScheduleFunctionType.SLEEP,
    detail: [currentNode],
  });
}
// 2.4.2 After successful deletion, useSleepDp (which automatically refreshes the value) to get the new sleepDpValue to refresh the page display.

// The "sleep module" above serves as an example to demonstrate the CRUD (Create, Read, Update, Delete) capabilities of module functions. Other modules are used similarly.
```