# EZOpenSDK Android 设备管理

## 设备管理模块 import 参考

```java
import com.videogo.openapi.EZOpenSDK;
import com.videogo.openapi.EZConstants;                                  // EZDefenceStatus、EZTalkbackCapability 等

// 设备信息对象（均在 com.videogo.openapi.bean 包下）
import com.videogo.openapi.bean.EZDeviceInfo;
import com.videogo.openapi.bean.EZCameraInfo;
import com.videogo.openapi.bean.EZSubDeviceInfo;
import com.videogo.openapi.bean.EZProbeDeviceInfo;
import com.videogo.openapi.bean.EZProbeDeviceInfoResult;
import com.videogo.openapi.bean.EZStorageStatus;
import com.videogo.openapi.bean.EZDeviceUpgradeStatus;
import com.videogo.openapi.bean.EZDeviceVersion;
import com.videogo.openapi.bean.EZUserInfo;
import com.videogo.openapi.bean.EZAccessToken;

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

### EZBusinessTool 工具类源码

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

```java
package com.videogo.ui.common; // 包名可自行调整

import android.text.TextUtils;
import com.videogo.openapi.EZConstants;
import com.videogo.openapi.bean.EZCameraInfo;
import com.videogo.openapi.bean.EZDeviceInfo;
import com.videogo.openapi.bean.EZSubDeviceInfo;

/**
 * SDK Demo 辅助工具类 - 兼容子设备能力集查询
 */
public class EZBusinessTool {

    /** 是否支持对讲（兼容子设备） */
    public static EZConstants.EZTalkbackCapability isSupportTalk(EZDeviceInfo deviceInfo, EZCameraInfo cameraInfo) {
        if (cameraInfo instanceof EZSubDeviceInfo) {
            return ((EZSubDeviceInfo) cameraInfo).isSupportTalk();
        }
        return deviceInfo.isSupportTalk();
    }

    /** 是否支持云台（兼容子设备） */
    public static boolean isSupportPTZ(EZDeviceInfo deviceInfo, EZCameraInfo cameraInfo) {
        if (cameraInfo instanceof EZSubDeviceInfo) {
            return ((EZSubDeviceInfo) cameraInfo).isSupportPTZ();
        }
        return deviceInfo.isSupportPTZ();
    }

    /** 是否支持回放倍率（兼容子设备） */
    public static boolean isSupportPlaybackRate(EZDeviceInfo deviceInfo, EZCameraInfo cameraInfo) {
        if (cameraInfo instanceof EZSubDeviceInfo) {
            return ((EZSubDeviceInfo) cameraInfo).isSupportPlaybackRate();
        }
        return deviceInfo.isSupportPlaybackRate();
    }

    /** 是否支持内网直连倍速（兼容子设备） */
    public static boolean isSupportDirectInnerRelaySpeed(EZDeviceInfo deviceInfo, EZCameraInfo cameraInfo) {
        if (cameraInfo instanceof EZSubDeviceInfo) {
            return ((EZSubDeviceInfo) cameraInfo).isSupportDirectInnerRelaySpeed();
        }
        return deviceInfo.isSupportDirectInnerRelaySpeed();
    }

    /** 是否支持 SD 卡录像下载（兼容子设备） */
    public static boolean isSupportSDRecordDownload(EZDeviceInfo deviceInfo, EZCameraInfo cameraInfo) {
        if (cameraInfo instanceof EZSubDeviceInfo) {
            return ((EZSubDeviceInfo) cameraInfo).isSupportSDRecordDownload();
        }
        return deviceInfo.isSupportSDRecordDownload();
    }

    /** 是否支持 SD 卡封面（兼容子设备） */
    public static boolean isSupportSdCover(EZDeviceInfo deviceInfo, EZCameraInfo cameraInfo) {
        if (cameraInfo instanceof EZSubDeviceInfo) {
            return ((EZSubDeviceInfo) cameraInfo).isSupportSdCover();
        }
        return deviceInfo.isSupportSdCover();
    }

    /** 是否支持光学缩放（兼容子设备） */
    public static boolean isSupportZoom(EZDeviceInfo deviceInfo, EZCameraInfo cameraInfo) {
        if (cameraInfo instanceof EZSubDeviceInfo) {
            return ((EZSubDeviceInfo) cameraInfo).isSupportZoom();
        }
        return deviceInfo.isSupportZoom();
    }

    /** 是否支持多通道（兼容子设备） */
    public static boolean isSupportMultiChannel(EZDeviceInfo deviceInfo, EZCameraInfo cameraInfo) {
        if (cameraInfo instanceof EZSubDeviceInfo) {
            return ((EZSubDeviceInfo) cameraInfo).isSupportMultiChannel();
        }
        return deviceInfo.isSupportMultiChannel();
    }

    /** 是否支持自动清晰度（兼容子设备） */
    public static boolean isSupportDeviceAutoVideolevel(EZDeviceInfo deviceInfo, EZCameraInfo cameraInfo) {
        if (cameraInfo instanceof EZSubDeviceInfo) {
            return ((EZSubDeviceInfo) cameraInfo).isSupportDeviceAutoVideolevel();
        }
        return deviceInfo.isSupportDeviceAutoVideolevel();
    }

    /**
     * 获取设备热点前缀
     * @param deviceHotSpot 0-EZVIZ，1-SoftAP，2-CAMGO
     */
    public static String getWiFiConfigPrefix(int deviceHotSpot) {
        switch (deviceHotSpot) {
            case 1: return "SoftAP";
            case 2: return "CAMGO";
            default: return "EZVIZ";
        }
    }
}
```

## 一、获取设备列表

### 获取用户设备列表
```java
// 基础设备列表
List<EZDeviceInfo> list = EZOpenSDK.getInstance().getDeviceList(int pageIndex, int pageSize);

// 包含子设备的设备列表
List<EZDeviceInfo> list = EZOpenSDK.getInstance().getDeviceListEx(int pageIndex, int pageSize);
```
- pageIndex 从 0 开始，pageSize 建议 20 以内
- 耗时操作，必须在子线程中调用

### 获取共享设备列表
```java
List<EZDeviceInfo> list = EZOpenSDK.getInstance().getSharedDeviceList(int pageIndex, int pageSize);
```

### 获取单个设备信息
```java
// 基础信息
EZDeviceInfo info = EZOpenSDK.getInstance().getDeviceInfo(String deviceSerial);

// 包含子设备
EZDeviceInfo info = EZOpenSDK.getInstance().getDeviceInfoEx(String deviceSerial);
```

## 二、EZDeviceInfo 属性详解

### 基础属性
| 属性 | 类型 | 获取方法 | 说明 |
|------|------|---------|------|
| deviceSerial | String | `getDeviceSerial()` | 设备 9 位序列号，唯一标识 |
| deviceName | String | `getDeviceName()` | 设备名称 |
| deviceType | String | `getDeviceType()` | 设备型号（IPC/DVR/报警设备等） |
| category | String | `getCategory()` | 设备大类 |
| status | int | `getStatus()` | 在线状态：1-在线，2-不在线 |
| isEncrypt | int | `getIsEncrypt()` | 是否加密：0-不加密，1-加密 |
| defence | int | `getDefence()` | 布撤防状态。IPC：0-撤防，1-布防；防护设备：0-睡眠，8-在家，16-外出 |
| deviceVersion | String | `getDeviceVersion()` | 设备固件版本号 |
| deviceCover | String | `getDeviceCover()` | 设备封面图片 URL |
| addTime | long | `getAddTime()` | 设备添加时间（毫秒） |
| cameraNum | int | `getCameraNum()` | 通道数量。IPC 为 1，4 通道 DVR 为 4 |
| offlineNotify | int | `getOfflineNotify()` | 下线通知：0-不通知，1-通知 |

### 关联对象
| 属性 | 类型 | 获取方法 | 说明 |
|------|------|---------|------|
| cameraInfoList | `List<EZCameraInfo>` | `getCameraInfoList()` | 通道列表 |
| detectorInfoList | `List<EZDetectorInfo>` | `getDetectorInfoList()` | 探测器列表 |
| subDeviceInfoList | `List<EZSubDeviceInfo>` | `getSubDeviceInfoList()` | 子设备列表（仅 Ex 接口返回） |

### 设备名称显示规则

显示设备名称时，**必须**处理名称为空的情况。规则如下：
- 优先使用 `getDeviceName()` 返回值
- 如果为空（null 或空字符串），则显示 `分类(序列号)` 格式

```java
// ✅ 正确 — 处理名称为空的 fallback
String displayName = device.getDeviceName();
if (TextUtils.isEmpty(displayName)) {
    String category = device.getCategory() != null ? device.getCategory() : "";
    displayName = String.format("%s(%s)", category, device.getDeviceSerial());
}

// ❌ 错误 — 直接使用 getDeviceName()，名称为空时 UI 显示空白
tvName.setText(device.getDeviceName());
```

### 能力集查询方法
| 方法 | 返回类型 | 说明 |
|------|---------|------|
| `isSupportTalk()` | EZTalkbackCapability | 对讲能力：NoSupport/FullDuplex/HalfDuplex |
| `isSupportDefence()` | boolean | 是否支持布撤防 |
| `isSupportPTZ()` | boolean | 是否支持云台控制 |
| `isSupportZoom()` | boolean | 是否支持光学缩放 |
| `isSupportUpgrade()` | boolean | 是否支持固件升级 |
| `isSupportSoundWave()` | boolean | 是否支持声波配网 |
| `isSupportPlaybackRate()` | boolean | 是否支持倍数回放 |
| `isSupportDirectInnerRelaySpeed()` | boolean | 内网直连下是否支持倍数回放 |
| `isSupportSDRecordDownload()` | boolean | 是否支持 SD 卡录像下载 |
| `isSupportSdCover()` | boolean | 是否支持 SD 卡视频封面 |
| `isSupportMultiChannel()` | boolean | 是否支持多通道（C7/C60P 等） |
| `isSupportDeviceAutoVideolevel()` | boolean | 是否支持自动清晰度 |
| `isSupportVideoMeeting()` | boolean | 是否支持视频会议 |
| `isSupportAudioOnOff()` | boolean | 是否支持麦克风声音开关 |
| `isSupportMirrorCenter()` | boolean | 是否支持中心镜像 |
| `isSupportPTZFocus()` | boolean | 是否支持云台焦距模式 |
| `isSupportDefencePlan()` | boolean | 是否支持布防计划 |

### 通用能力集查询
当 EZDeviceInfo 未提供某些能力集查询方法时，使用以下通用方法：
```java
// 获取 int 值
int value = deviceInfo.getSupportInt(int index);

// 获取原始字符串值
String value = deviceInfo.getSupportValue(int index);
```
index 对应能力集位数，参见萤石开放平台能力集文档。

示例：
```java
// 判断是否是电池设备：(0)不使用电池 (1)一块电池 (2)两块电池
int batteryType = deviceInfo.getSupportInt(322);

// 获取画面宽高比
String videoRadio = deviceInfo.getSupportValue(16); // 返回 "16-9"
```

## 三、EZCameraInfo 属性详解

| 属性 | 类型 | 获取方法 | 说明 |
|------|------|---------|------|
| deviceSerial | String | `getDeviceSerial()` | 设备序列号 |
| cameraNo | int | `getCameraNo()` | 通道号，IPC 始终为 1 |
| cameraName | String | `getCameraName()` | 通道名称 |
| isShared | int | `getIsShared()` | 分享状态：0-未分享，1-分享所有者，2-分享接受者 |
| cameraCover | String | `getCameraCover()` | 通道封面 URL |
| videoLevel | EZVideoLevel | `getVideoLevel()` | 清晰度：0-流畅，1-均衡，2-高清，3-超清，4-极清，5-3K，6-4K |
| videoQualityInfos | `ArrayList<EZVideoQualityInfo>` | `getVideoQualityInfos()` | 支持的清晰度列表 |

## 四、设备添加与删除

### 添加设备
```java
boolean success = EZOpenSDK.getInstance().addDevice(String deviceSerial, String verifyCode);
```
- verifyCode 为设备验证码，位于设备机身标签上，6 位大写字母

### 删除设备
```java
boolean success = EZOpenSDK.getInstance().deleteDevice(String deviceSerial);
```

## 五、设备信息修改

### 修改设备名称
```java
boolean success = EZOpenSDK.getInstance().setDeviceName(String deviceSerial, String deviceName);
```

### 设备加密开关
```java
boolean success = EZOpenSDK.getInstance().setDeviceEncryptStatus(String deviceSerial, String validateCode, boolean encrypt);
```

### 布防状态设置
```java
boolean success = EZOpenSDK.getInstance().setDefence(String deviceSerial, EZConstants.EZDefenceStatus defence);
```
EZDefenceStatus 枚举值：
- `EZDefence_IPC_CLOSE` (0) - IPC 关闭布防（撤防）
- `EZDefence_IPC_OPEN` (1) - IPC 开启布防
- `EZDefence_ALARMHOST_SLEEP` (0) - 报警器睡眠
- `EZDefence_ALARMHOST_ATHOME` (8) - 报警器在家
- `EZDefence_ALARMHOST_OUTER` (16) - 报警器外出

## 六、设备版本与升级

### 获取设备版本
```java
EZDeviceVersion version = EZOpenSDK.getInstance().getDeviceVersion(String deviceSerial);
```

### 获取升级状态
```java
EZDeviceUpgradeStatus status = EZOpenSDK.getInstance().getDeviceUpgradeStatus(String deviceSerial);
```

### 开始升级
```java
EZOpenSDK.getInstance().upgradeDevice(String deviceSerial);
```

## 七、存储管理

### 获取存储状态
```java
List<EZStorageStatus> statusList = EZOpenSDK.getInstance().getStorageStatus(String deviceSerial);
```
返回列表每个 item 代表一个磁盘分区。

### 格式化 SD 卡
```java
boolean success = EZOpenSDK.getInstance().formatStorage(String deviceSerial, int partitionIndex);
```
partitionIndex 为 getStorageStatus 返回的分区号。

## 八、设备探测

用于添加设备之前查询设备信息：
```java
EZProbeDeviceInfoResult result = EZOpenSDK.getInstance().probeDeviceInfo(String deviceSerial, String deviceType);
```

EZProbeDeviceInfo 对象方法：
| 方法 | 说明 |
|------|------|
| `getSupportAP()` | 是否支持 AP 配网，2-支持 |
| `getSupportSoundWave()` | 是否支持声波配网，0-不支持，1-支持 |
| `getSupportWifi()` | 是否支持 WiFi，0-不支持，1-支持，2-带 userId，3-smartwifi |
| `getSupportAPType()` | AP 配网协议类型，1-HTTP，2-NETSDK |
| `getDeviceHotSpot()` | 设备热点前缀类型，0-EZVIZ，1-SoftAP，2-CAMGO |

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

## 九、设备详情刷新

修改验证码后需调用：
```java
EZOpenSDK.getInstance().refreshDeviceDetailInfo(String deviceSerial, int cameraNo);
```

## 十、获取用户信息
```java
EZUserInfo userInfo = EZOpenSDK.getInstance().getUserInfo();
```

## 十一、抓图（设备端）

给在线设备下发信令，让设备上传当前图片到云端（保留 2 小时），不要求在取流过程中：
```java
String imageUrl = EZOpenSDK.getInstance().captureCamera(String deviceSerial, int cameraNo);
```
应用场景：抓图作为设备封面。

## 十二、EZBusinessTool 辅助工具类

提供能力集判断的便捷方法（兼容子设备）：
```java
// 是否支持对讲
EZConstants.EZTalkbackCapability capability = EZBusinessTool.isSupportTalk(deviceInfo, cameraInfo);

// 是否支持云台
boolean supportPTZ = EZBusinessTool.isSupportPTZ(deviceInfo, cameraInfo);

// 是否支持倍数回放
boolean supportRate = EZBusinessTool.isSupportPlaybackRate(deviceInfo, cameraInfo);

// 是否支持 SD 卡录像下载
boolean supportDownload = EZBusinessTool.isSupportSDRecordDownload(deviceInfo, cameraInfo);

// 是否支持 SD 卡封面
boolean supportCover = EZBusinessTool.isSupportSdCover(deviceInfo, cameraInfo);

// 是否支持光学缩放
boolean supportZoom = EZBusinessTool.isSupportZoom(deviceInfo, cameraInfo);

// 是否支持多通道
boolean supportMulti = EZBusinessTool.isSupportMultiChannel(deviceInfo, cameraInfo);

// 是否支持自动清晰度
boolean supportAuto = EZBusinessTool.isSupportDeviceAutoVideolevel(deviceInfo, cameraInfo);

// 获取设备热点前缀
String prefix = EZBusinessTool.getWiFiConfigPrefix(int deviceHotSpot);
```
