## Log Management

Door lock records are divided into three categories: album records, alarm records, and log records.

### Album Records

- Locks that support video and image capture will have such records, which contain images and videos, usually generated when someone rings the doorbell, someone stays, etc.;
- For security reasons, Tuya encrypts images and videos, and developers need to use specific capabilities and solutions to display them normally.

For image processing solutions, please refer to: [Media Image Processing](/en/miniapp/solution-ai/ability/doorlock-solution/media/photo)

For video processing solutions, please refer to: [Media Video Processing](/en/miniapp/solution-ai/ability/doorlock-solution/media/video)

#### Alarm Records

Records generated when the door lock alarms, including alarms such as: anti-prying, password error attempts, fingerprint error attempts, loitering, hijacking, low battery, etc.

### Log Records

Record types include

- close_record indicates lock closing log
- unlock_record indicates unlock log
- operation indicates operation log
- local_operation indicates device local operation log
- dev_bind indicates device binding log

### Log Text Processing

Alarm Processing

```jsx

export const codeOnlyShowDpCodeText = [
  'doorbell',
  'unlock_offline_clear',
  'unlock_offline_clear_single',
];
const getText = (log) => {
    const text = codeOnlyShowDpCodeText.includes(log.dpCode)
        ? Strings.getDpLang(log.dpCode)
        : Strings.getDpLang(log.dpCode, log.data as string);
    if (log.isHijack) {
        // Whether hijacked
        return `${Strings.getDpLang('hijack')}【${text}】`;
    }
    return text;
}
```

Lock Closing Log

```
const text = Strings.getLang(`locked_${log.closeValue}`);

```

Local Operation Record

```tsx

import {
  LocalOperateCategory,
  LocalSettingData,
  LocalUnlockMethodData,
  LogData,
} from '@ray-js/lock-sdk';

const getLocalOperationText = (log: LogData) => {
  if (!log.localRecord) {
    return Strings.getLang('unkownLocalOperation');
  }

  const { category, userId, userType, toUserType, toUserId } = log.localRecord;
  switch (category) {
    case LocalOperateCategory.DELETE_UNLOCK_METHOD: {
      const { unlockMethod, unlockId, isRemoveAll } = log.localRecord as LocalUnlockMethodData;
      if (isRemoveAll) {
        return Strings.formatValue(
          'localDeleteAllUnlockMethod',
          Strings.getLang(`localUser${userType}`),
          userId,
          Strings.getLang(`localUser${toUserType}`),
          toUserId,
          Strings.getLang(unlockMethod)
        );
      }
      return Strings.formatValue(
        'deleteUnlockMethod',
        Strings.getLang(`localUser${userType}`),
        userId,
        Strings.getLang(`localUser${toUserType}`),
        toUserId,
        Strings.getLang(unlockMethod),
        unlockId
      );
    }
    case LocalOperateCategory.ADD_UNLOCK_METHOD: {
      const { unlockMethod, unlockId } = log.localRecord as LocalUnlockMethodData;
      return Strings.formatValue(
        'localAddUnlockMethod',
        Strings.getLang(`localUser${userType}`),
        userId,
        Strings.getLang(`localUser${toUserType}`),
        toUserId,
        Strings.getLang(unlockMethod),
        unlockId
      );
    }
    case LocalOperateCategory.MODIFY_UNLOCK_METHOD: {
      const { unlockMethod, unlockId } = log.localRecord as LocalUnlockMethodData;
      return Strings.formatValue(
        'localModifyUnlockMethod',
        Strings.getLang(`localUser${userType}`),
        userId,
        Strings.getLang(`localUser${toUserType}`),
        toUserId,
        Strings.getLang(unlockMethod),
        unlockId
      );
    }
    case LocalOperateCategory.ADD_USER:
      return Strings.formatValue(
        'localAddUser',
        Strings.getLang(`localUser${userType}`),
        userId,
        Strings.getLang(`localUser${toUserType}`),
        toUserId
      );
    case LocalOperateCategory.DELETE_USER:
      return Strings.formatValue(
        'localDeleteUser',
        Strings.getLang(`localUser${userType}`),
        userId,
        Strings.getLang(`localUser${toUserType}`),
        toUserId
      );
    case LocalOperateCategory.SETTING: {
      const { type, data } = log.localRecord as LocalSettingData;
      /**
       * Multilingual key rules for configuration data:
       * Name key: localSetting_{type};
       * Value key: localSetting_{type}_{data};
       */
      if (typeof data === 'number') {
        return Strings.formatValue(
          'localSetting',
          Strings.getLang(`localUser${userType}`),
          userId,
          // @ts-expect-error
          Strings.getLang(`localSetting_${type}`),
          // @ts-expect-error
          Strings.getLang(`localSetting_${type}_${data}`)
        );
      }
      return Strings.formatValue(
        'localSetting1',
        Strings.getLang(`localUser${userType}`),
        userId,
        // @ts-expect-error
        Strings.getLang(`localSetting_${type}`)
      );
    }
    default:
      return Strings.getLang('unkownLocalOperation');
  }
};
```

Operation Log

```tsx
const {
    property: { type, scale, unit },
} = dpSchema[log.dpCode] || {};
switch (type) {
case 'value':
    return Strings.formatValue(
    'settingRecord',
    Strings.getDpLang(log.dpCode),
    `${utils.scaleNumber(scale, log.data as number)}${Strings.getDpLang(
        log.dpCode,
        'unit'
    )}`
    );
case 'enum':
    return Strings.formatValue(
    'settingRecord',
    Strings.getDpLang(log.dpCode),
    Strings.getDpLang(log.dpCode, log.data as string)
    );
case 'bool':
    return Strings.formatValue(
    'settingRecord',
    Strings.getDpLang(log.dpCode),
    Strings.getDpLang(log.dpCode, log.data as boolean)
    );
default:
    return Strings.getDpLang(log.dpCode);
}
```

Unlock Log

```tsx

import {
  getCurrentUserSync,
  LocalOperateCategory,
  LocalSettingData,
  LocalUnlockMethodData,
  LogData,
  unlockDp2Type,
} from '@ray-js/lock-sdk';

const getUnlockText = (log: LogData) => {
  const user = getCurrentUserSync();
  // Whether it is a combined unlock
  if (log.unionUnlockInfo?.length) {
    const logText = log.unionUnlockInfo
      .map(item => {
        let { userName } = item;
        if (item.userId === user?.userId) {
          userName = Strings.getLang('you');
        }
        return Strings.formatValue(
          'unlockFormat',
          userName,
          item.unlockName ? item.unlockName : Strings.getLang(item.type)
        );
      })
      .join('、');
    return Strings.formatValue('unionUnlock', logText);
  }
  if (log.userName && log.unlockName) {
    // If user and unlock name exist, it indicates a user operation
    return Strings.formatValue(
      'unlockFormat',
      log.userId === user?.userId ? Strings.getLang('you') : log.userName,
      log.unlockName
    );
  }
  // When there is a name
  if (log.unlockName) {
    return Strings.formatValue('unlockFormat1', log.unlockName);
  }

  // The following handles cases without names
  // Temporary or offline password processing
  if ([69, 89].indexOf(log.dpId) !== -1) {
    // Temporary or offline password processing
    return Strings.getDpLang(log.dpCode);
  }
  // Some special unlocks
  if (codeOnlyShowDpCodeText.includes(log.dpCode)) {
    return Strings.getDpLang(log.dpCode);
  }

  // Unlock method processing
  if (unlockDp2Type[log.dpCode]) {
    return Strings.formatValue(
      'unlockFormat2',
      Strings.getLang(unlockDp2Type[log.dpCode]),
      log.data
    );
  }

  return Strings.getDpLang(log.dpCode);
};
```

### API

#### Get Latest 2 Records

- Meaning: Get the latest 2 records, including alarms, unlocks, lock closings, operation logs, etc.
- Details: [View Documentation](/en/miniapp/develop/ray/api/doorlock/log/getLatestLogs)

#### Get Log Records

- Meaning: Get log records, including unlock, lock closing, operation, local operation logs, etc.
- Details: [View Documentation](/en/miniapp/develop/ray/api/doorlock/log/getLogs)

#### Get Alarm List

- Meaning: Get alarm record list
- Details: [View Documentation](/en/miniapp/develop/ray/api/doorlock/log/getAlarms)

#### Get Album Logs

- Meaning: Get album logs
- Details: [View Documentation](/en/miniapp/develop/ray/api/doorlock/log/getAlbums)

#### Register Log Refresh Notification Event

- Meaning: This event is triggered when related record DP reports are received
- Details: [View Documentation](/en/miniapp/develop/ray/api/doorlock/log/onLogsRefresh)

#### Unregister Log Refresh Notification Event

- Meaning: Unregister the event registered through `onLogsRefresh`
- Details: [View Documentation](/en/miniapp/develop/ray/api/doorlock/log/offLogsRefresh)

## FAQ

### Q1: How to distinguish different types of logs?

**A:** Distinguish by the `type` field:

- `unlock_record`: Unlock record
- `close_record`: Lock closing record
- `alarm_record`: Alarm record
- `dev_bind`: Device binding record
- `local_operation`: Local operation record

### Q2: How to determine if a log can be bound to a member?

**A:** Determine by the `bindable` field. If it is `true`, it means the unlock method in this log can be bound to a member.

### Q3: How to get media files in logs?

**A:** The `mediaInfo` field in the log object contains media information. Use the `getMediaUrl` API to get the actual playback address:

```typescript
const mediaUrl = await getMediaUrl({
  mediaPath: log.mediaInfo[0].mediaPath,
  mediaBucket: log.mediaInfo[0].mediaBucket
});
```

### Q4: What is union unlock information?

**A:** `unionUnlockInfo` represents information about multiple people unlocking together, including the users and unlock methods involved in the unlock.

### Q5: How to implement real-time log updates?

**A:** Use `onLogsRefresh` to listen for log update events:

```typescript
onLogsRefresh(() => {
  // Re-fetch log list
  fetchLogs();
});
```

### Q6: Which devices support album records?

**A:** Album records only support video intercom devices (door lock devices with cameras).

### Q7: How to get the unread log count?

**A:** Use the `getLatestLogs` API. The `unreadCount` field in the returned result indicates the unread count.
