# EZOpenSDK iOS 设备管理

## 设备管理模块 import 参考

```objc
#import <EZOpenSDKFramework/EZOpenSDK.h>
#import <EZOpenSDKFramework/EZDeviceInfo.h>
#import <EZOpenSDKFramework/EZCameraInfo.h>
#import <EZOpenSDKFramework/EZSubDeviceInfo.h>
#import <EZOpenSDKFramework/EZProbeDeviceInfo.h>

// 注意：EZBusinessTool 不是 SDK 中的类，而是 Demo 工程中的辅助工具类。
// 它的核心作用是兼容子设备（EZSubDeviceInfo）的能力集查询。
// 使用时需将下方源码复制到自己的工程中。
```

### EZBusinessTool 工具类源码

`EZBusinessTool` 在 skill 文档的多个模块中被引用（设备管理、播放器、对讲、配网），但它不在 SDK 中，需要开发者自行集成。核心逻辑：网关子设备的能力集挂载在 `EZSubDeviceInfo` 自身，而非父设备 `EZDeviceInfo`，因此需要做类型判断。

```objc
#import "EZBusinessTool.h"
#import <EZOpenSDKFramework/EZDeviceInfo.h>
#import <EZOpenSDKFramework/EZCameraInfo.h>
#import <EZOpenSDKFramework/EZSubDeviceInfo.h>

@implementation EZBusinessTool

/** 是否支持对讲（兼容子设备） */
+ (NSInteger)isSupportTalk:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportTalk;
    }
    return deviceInfo.isSupportTalk;
}

/** 是否支持云台（兼容子设备） */
+ (BOOL)isSupportPTZ:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportPTZ;
    }
    return deviceInfo.isSupportPTZ;
}

/** 是否支持回放倍率（兼容子设备） */
+ (BOOL)isSupportPlaybackRate:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportPlaybackRate;
    }
    return deviceInfo.isSupportPlaybackRate;
}

/** 是否支持内网直连倍速（兼容子设备） */
+ (BOOL)isSupportDirectInnerRelaySpeed:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportDirectInnerRelaySpeed;
    }
    return deviceInfo.isSupportDirectInnerRelaySpeed;
}

/** 是否支持 SD 卡录像下载（兼容子设备） */
+ (BOOL)isSupportSDRecordDownload:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportSDRecordDownload;
    }
    return deviceInfo.isSupportSDRecordDownload;
}

/** 是否支持 SD 卡封面（兼容子设备） */
+ (BOOL)isSupportSdCover:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportSdCover;
    }
    return deviceInfo.isSupportSdCover;
}

/** 是否支持多通道（兼容子设备） */
+ (BOOL)isSupportMultiChannel:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportMultiChannel;
    }
    return deviceInfo.isSupportMultiChannel;
}

/** 是否支持自动清晰度（兼容子设备） */
+ (BOOL)isSupportDeviceAutoVideolevel:(EZDeviceInfo *)deviceInfo cameraInfo:(EZCameraInfo *)cameraInfo {
    if ([cameraInfo isKindOfClass:[EZSubDeviceInfo class]]) {
        EZSubDeviceInfo *subDeviceInfo = (EZSubDeviceInfo *)cameraInfo;
        return subDeviceInfo.isSupportDeviceAutoVideolevel;
    }
    return deviceInfo.isSupportDeviceAutoVideolevel;
}

/** 获取设备热点前缀 */
+ (NSString *)getWiFiConfigPrefix:(NSInteger)deviceHotSpot {
    switch (deviceHotSpot) {
        case 1: return @"SoftAP";
        case 2: return @"CAMGO";
        default: return @"EZVIZ";
    }
}

@end
```

## 一、获取设备列表

```objc
// 基础设备列表
[EZOpenSDK getDeviceList:pageIndex pageSize:pageSize completion:^(NSArray *deviceList, NSInteger totalCount, NSError *error) {
    // deviceList 为 EZDeviceInfo 数组
}];

// 包含子设备的设备列表
[EZOpenSDK getDeviceListEx:pageIndex pageSize:pageSize completion:^(NSArray *deviceList, NSInteger totalCount, NSError *error) {
}];
```
- pageIndex 从 0 开始，pageSize 建议 20 以内

## 二、获取单个设备信息

```objc
[EZOpenSDK getDeviceInfo:deviceSerial completion:^(EZDeviceInfo *deviceInfo, NSError *error) {
}];

// 包含子设备
[EZOpenSDK getDeviceInfoEx:deviceSerial completion:^(EZDeviceInfo *deviceInfo, NSError *error) {
}];
```

## 三、EZDeviceInfo 属性详解

### 基础属性
| 属性 | 类型 | 说明 |
|------|------|------|
| deviceSerial | NSString | 设备 9 位序列号，唯一标识 |
| deviceName | NSString | 设备名称 |
| deviceType | NSString | 设备型号 |
| category | NSString | 设备大类 |
| status | NSInteger | 在线状态：1-在线，2-不在线 |
| isEncrypt | BOOL | 是否加密 |
| defence | NSInteger | 布撤防状态 |
| deviceVersion | NSString | 设备固件版本号 |
| deviceCover | NSString | 设备封面图片 URL |
| addTime | NSDate | 设备添加时间 |
| cameraNum | NSInteger | 通道数量 |

### 关联对象
| 属性 | 类型 | 说明 |
|------|------|------|
| cameraInfo | NSArray | 通道列表（EZCameraInfo 数组） |
| detectorInfo | NSArray | 探测器列表 |
| subDeviceInfo | NSArray | 子设备列表（仅 Ex 接口返回） |

### 能力集查询属性

**注意**：以下属性均为计算型属性，须调用后才能查看具体的值。

| 属性 | 类型 | 说明 |
|------|------|------|
| isSupportTalk | NSInteger | 对讲能力：0-不支持，1-全双工，3-半双工，4-都支持 |
| isSupportPTZ | BOOL | 是否支持云台控制 |
| isSupportZoom | BOOL | 是否支持光学缩放 |
| isSupportPlaybackRate | BOOL | 是否支持倍数回放 |
| isSupportDirectInnerRelaySpeed | BOOL | 内网直连下是否支持倍数回放 |
| isSupportSDRecordDownload | BOOL | 是否支持 SD 卡录像下载 |
| isSupportSdCover | BOOL | 是否支持 SD 卡视频封面 |
| isSupportMultiChannel | BOOL | 是否支持多通道 |
| isSupportDeviceAutoVideolevel | BOOL | 是否支持自动清晰度 |

### 通用能力集查询
```objc
// 获取 int 值
int value = [deviceInfo getSupportInt:index];

// 获取原始字符串值
NSString *value = [deviceInfo getSupportValue:index];
```

## 四、设备添加与删除

### 添加设备
```objc
[EZOpenSDK addDevice:deviceSerial verifyCode:verifyCode completion:^(NSError *error) {
    if (!error) {
        // 添加成功
    }
}];
```

### 删除设备
```objc
[EZOpenSDK deleteDevice:deviceSerial completion:^(NSError *error) {
}];
```

## 五、设备信息修改

### 修改设备名称
```objc
// 注意参数顺序：先 deviceName 后 deviceSerial
[EZOpenSDK setDeviceName:newName deviceSerial:deviceSerial completion:^(NSError *error) {
}];
```

### 设备加密开关
```objc
// 开启加密：verifyCode 传空字符串即可，不需要用户输入验证码
[EZOpenSDK setDeviceEncryptStatus:deviceSerial verifyCode:@"" encrypt:YES completion:^(NSError *error) {
}];

// 关闭加密：需要传入设备验证码
[EZOpenSDK setDeviceEncryptStatus:deviceSerial verifyCode:verifyCode encrypt:NO completion:^(NSError *error) {
}];
```
> ⚠️ 业务规则：开启加密不需要验证码（传空字符串），关闭加密必须输入设备验证码。

### 布防状态设置
```objc
[EZOpenSDK setDefence:EZDefenceStatusOpen deviceSerial:deviceSerial completion:^(NSError *error) {
}];
```

## 六、设备探测

用于添加设备之前查询设备信息：
```objc
[EZOpenSDK probeDeviceInfo:deviceSerial deviceType:nil completion:^(EZProbeDeviceInfo *deviceInfo, NSError *error) {
    if (error) {
        NSInteger code = error.code;
        // 根据错误码处理
    } else {
        // 设备在线，可直接添加
    }
}];
```

EZProbeDeviceInfo 对象属性：
| 属性 | 说明 |
|------|------|
| supportAP | 是否支持 AP 配网，2-支持 |
| supportSoundWave | 是否支持声波配网，0-不支持，1-支持 |
| supportWifi | 是否支持 WiFi，0-不支持，1-支持，2-带 userId，3-smartwifi |
| supportAPType | AP 配网协议类型，1-HTTP，2-NETSDK |
| deviceHotSpot | 设备热点前缀类型，0-EZVIZ，1-SoftAP，2-CAMGO |

错误码处理：
| 错误码 | 含义 | 处理 |
|--------|------|------|
| 120020 | 设备在线，已被自己添加 | 提示用户 |
| 120021 | 设备在线，未被添加 | 可直接添加 |
| 120022 | 设备在线，已被别人添加 | 提示用户 |
| 120023 | 设备不在线，未被添加 | 需要配网 |
| 120024 | 设备不在线，已被别人添加 | 提示用户 |
| 120029 | 设备不在线，已被自己添加 | 需要配网 |
| 120002 | 设备不存在 | 需要配网 |

## 七、抓图（设备端）

给在线设备下发信令，让设备上传当前图片到云端（保留 2 小时），不要求在取流过程中：
```objc
[EZOpenSDK captureCamera:deviceSerial cameraNo:cameraNo completion:^(NSString *url, NSError *error) {
    // url 为图片地址
}];
```
应用场景：抓图作为设备封面。
