Featured image of post 海康摄像头接入萤石云:AppKey/Secret 申请、Token 获取、设备添加、直播地址

海康摄像头接入萤石云:AppKey/Secret 申请、Token 获取、设备添加、直播地址

海康威视摄像头接入萤石云开放平台完整流程:AppKey/Secret 申请、accessToken 获取、设备序列号与验证码、添加设备、直播地址获取、消息订阅

一、为什么"萤石云"是海康的官方上云通道

海康威视 2015 年推出"萤石云"(ezviz),是海康官方的 IoT 平台。接入萤石云开放平台有几个典型收益:

  • 远程观看:自带萤石云 App / Web 客户端,无需自建流媒体服务
  • P2P 打洞摄像头无需公网 IP穿透内网直接访问
  • 录像 / 告警 / 云存储:海康官方运维,不占本地存储
  • 多端 SDK:Web / iOS / Android / 小程序 SDK 全有

对接的核心是萤石云开放平台(open.ys7.com)——海康的所有摄像头都能接(不只是萤石云品牌)。

二、硬件准备

2.1 摄像头配置

海康摄像头默认已经支持萤石云接入——只需在摄像头后台开启"萤石云服务":

1
2
3
4
5
6
1. 摄像头 Web 后台(默认 http://192.168.1.64)
2. 网络 → 平台接入
3. 启用"萤石云"
4. 记下两个关键参数:
   - 设备序列号(9 位数字 / 字母)
   - 验证码(6 位大写字母,印在机身标签上)

关键设备序列号的字母必须大写——这是萤石云 API 强制的。

2.2 网络要求

  • 摄像头能访问公网(萤石云域名 open.ys7.com
  • 不需要固定公网 IP(P2P 打洞)
  • 不要把摄像头放在 DMZ——萤石云有白名单校验

三、注册萤石云开放平台账号

3.1 注册入口

地址:https://open.ys7.com/

1
2
3
4
5
6
1. 注册开发者账号
2. 进入"我的应用" → "创建应用"
3. 填写应用名称、类型
4. 创建成功后,拿到:
   - AppKey
   - AppSecret

AppKey 和 AppSecret 是开放平台的唯一身份标识——所有 API 调用都基于这两个参数

3.2 应用类型选择

  • Web 应用 —— 浏览器端 JS 调用
  • 移动 App —— iOS / Android
  • 服务端应用 —— 纯后端调用(最常用——服务器拉取设备列表 / 直播地址

四、获取 accessToken

4.1 接口说明

1
2
3
4
5
6
7
URL: https://open.ys7.com/api/lapp/token/get
Method: POST
Content-Type: application/x-www-form-urlencoded

请求参数:
  appKey:    <你的 AppKey>
  appSecret: <你的 AppSecret>

4.2 返回数据

1
2
3
4
5
6
7
8
{
  "data": {
    "accessToken": "at.7jrcjmna8qnqg8d3dgnzs87m4v2dme3l-32enpqgusd-1jvdfe4-uxo15ik0s",
    "expireTime": 1470810222045
  },
  "code": "200",
  "msg": "操作成功!"
}

accessToken 有效期 7 天——需要缓存(不要每次调用都请求一次)。

4.3 错误码

错误码描述
200请求成功
10001参数错误(appKey/appSecret 为空或格式错)
10005appKey 被冻结
10017appKey 不存在
10030appKey 和 appSecret 不匹配
49999接口异常

4.4 curl 示例

1
2
3
curl -X POST https://open.ys7.com/api/lapp/token/get \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "appKey=YOUR_APPKEY&appSecret=YOUR_APPSECRET"

五、添加设备

5.1 文档地址

https://open.ys7.com/doc/zh/book/index/device_option.html#device_option-api1

5.2 接口

1
2
3
4
5
6
7
8
URL: https://open.ys7.com/api/lapp/device/add
Method: POST
Content-Type: application/x-www-form-urlencoded

请求参数:
  accessToken:   <上一步拿到的 accessToken>
  deviceSerial:  <设备序列号>  # 字母必须大写
  validateCode:  <验证码>      # 6 位大写字母

5.3 返回示例

1
2
3
4
{
  "code": "200",
  "msg": "操作成功"
}

code: 200 表示添加成功。

5.4 注意事项

  • 设备必须先在摄像头 Web 后台启用萤石云
  • 一个 AppKey 可以添加多个设备——没有数量限制但单 AppKey 调用频率有限制
  • 设备添加后立即生效——Web / App 端登录同一个萤石云账号就能看到

六、获取直播地址

6.1 接口

1
2
3
URL: https://open.ys7.com/api/lapp/v2/live/address/get
Method: POST
Content-Type: application/x-www-form-urlencoded

6.2 请求参数

参数类型必选描述
accessTokenStringY上一步拿到的 accessToken
deviceSerialStringY设备序列号,限制 50 字符
channelNoIntegerN通道号,默认 1
codeStringNezopen 协议的视频加密密码
expireTimeIntegerN过期时长(秒),30 - 720 天
protocolIntegerN协议:1-ezopen / 2-hls / 3-rtmp / 4-flv,默认 1
qualityIntegerN清晰度:1-高清 / 2-流畅
supportH265IntegerN是否 H.265:1-需要 / 0-不要求

6.3 返回示例

1
2
3
4
5
6
7
8
9
{
  "code": "200",
  "msg": "操作成功,获取指定有效期的直播地址",
  "data": {
    "id": "...",
    "url": "ezopen://open.ys7.com/BC9729213/1.hd.live",
    "expireTime": 1694764800
  }
}

返回的 url 字段就是直播地址——浏览器 / VLC / 萤石云 App 都能直接播

6.4 协议对比

协议浏览器支持延迟适用
ezopen❌(萤石云私有协议1-2s萤石云 App / SDK
hls✅ Safari 原生 / Chrome 需 video.js5-10sWeb 端最稳
rtmp❌ Flash 88+ 已删1-2s老项目
flv✅ via video.js HTTP-FLV1-2sWeb 端低延迟

七、消息订阅(告警 / 事件推送)

7.1 订阅事件

1
2
3
4
5
curl --location --request POST \
  'https://open.ys7.com/api/open/cloud/ISAPI/Event/notification/subscribeEvent' \
  --header 'User-Agent: apifox/1.0.0 (https://www.apifox.cn)' \
  --data-urlencode 'accessToken=at.your_token_here' \
  --data-urlencode 'deviceSerial=YOUR_DEVICE_SERIAL'

事件类型

  • 移动侦测(motion)
  • 视频遮挡(videoBlind)
  • 声音异常(audio异常)
  • IO 报警(外接红外 / 门磁)

7.2 拉取告警列表

1
2
3
4
5
curl --location --request POST \
  'https://open.ys7.com/api/lapp/alarm/device/list' \
  --header 'User-Agent: apifox/1.0.0 (https://www.apifox.cn)' \
  --data-urlencode 'accessToken=at.your_token_here' \
  --data-urlencode 'deviceSerial=YOUR_DEVICE_SERIAL'

返回形如:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
{
  "code": "200",
  "data": [
    {
      "alarmId": "...",
      "alarmName": "移动侦测",
      "alarmTime": "2024-12-15 10:30:00",
      "channelNo": 1,
      "deviceSerial": "..."
    }
  ]
}

八、Java 后端封装

8.1 依赖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version>
</dependency>
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.43</version>
</dependency>

8.2 TokenService

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
@Service
public class Ys7TokenService {

    private static final String APP_KEY = "your_app_key";
    private static final String APP_SECRET = "your_app_secret";
    private static final String TOKEN_URL = "https://open.ys7.com/api/lapp/token/get";

    // 缓存 token
    private String cachedToken;
    private long expireTime = 0;

    public synchronized String getAccessToken() {
        if (cachedToken != null && System.currentTimeMillis() < expireTime) {
            return cachedToken;
        }

        OkHttpClient client = new OkHttpClient();
        RequestBody body = new FormBody.Builder()
            .add("appKey", APP_KEY)
            .add("appSecret", APP_SECRET)
            .build();

        Request request = new Request.Builder()
            .url(TOKEN_URL)
            .post(body)
            .build();

        try (Response response = client.newCall(request).execute()) {
            String json = response.body().string();
            JSONObject data = JSON.parseObject(json).getJSONObject("data");
            cachedToken = data.getString("accessToken");
            expireTime = data.getLong("expireTime") - 86400_000L; // 提前 1 天刷新
            return cachedToken;
        } catch (IOException e) {
            throw new RuntimeException("获取萤石云 token 失败", e);
        }
    }
}

8.3 设备添加

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Service
public class Ys7DeviceService {

    @Autowired
    private Ys7TokenService tokenService;

    public boolean addDevice(String deviceSerial, String validateCode) {
        // 字母必须大写
        deviceSerial = deviceSerial.toUpperCase();
        validateCode = validateCode.toUpperCase();

        OkHttpClient client = new OkHttpClient();
        RequestBody body = new FormBody.Builder()
            .add("accessToken", tokenService.getAccessToken())
            .add("deviceSerial", deviceSerial)
            .add("validateCode", validateCode)
            .build();

        Request request = new Request.Builder()
            .url("https://open.ys7.com/api/lapp/device/add")
            .post(body)
            .build();

        try (Response response = client.newCall(request).execute()) {
            String json = response.body().string();
            return "200".equals(JSON.parseObject(json).getString("code"));
        } catch (IOException e) {
            throw new RuntimeException("添加设备失败", e);
        }
    }
}

九、调用频率限制

萤石云开放平台有调用频率限制

  • token 接口:每个 AppKey 每分钟 60 次
  • 设备 / 直播地址接口:每个 AppKey 每分钟 120 次

生产建议

  • accessToken 缓存 7 天(设过期前 1 天主动刷新)
  • 设备列表本地缓存**(摄像头不轻易变化)**
  • 直播地址按需获取,短期缓存 5-10 分钟

十、常见 5 个坑

  1. 设备序列号字母必须大写——deviceSerial.toUpperCase() 是基本操作
  2. accessToken 每次调 token 接口——会触发频率限制——必须本地缓存
  3. 添加设备失败但摄像头 Web 后台能看到萤石云在线——AppKey 没绑定到具体设备——重新走 device/add
  4. 直播地址过期——默认 expireTime = 7 天——生产建议设 30 天 + 提前刷新
  5. 告警事件收不到——没订阅事件——先调 subscribeEvent 才会推送

十一、安全注意

  • AppSecret 必须服务端存储——不能放到前端 / 客户端会被反编译 / 抓包
  • 设备验证码只用于首次添加——建议添加成功后丢弃不要长期存数据库
  • accessToken 不要写日志——走日志脱敏(参考 .claude/docs/0.5-batch-guide.md)

十二、总结

  • 萤石云开放平台 = 海康官方 IoT 云——AppKey/Secret 申请 → token 获取 → 设备添加 → 直播地址
  • accessToken 7 天有效——必须服务端缓存避免触发频率限制
  • 设备序列号 + 验证码——字母必须大写——6 位大写字母印在机身
  • 直播地址协议 = ezopen(私有)/ hls(web 稳)/ flv(web 低延迟)
  • 消息订阅 = subscribeEvent + alarm/device/list 拉取
  • 生产建议 = AppSecret 走服务端 + token 缓存 7 天 + 直播地址 5-10 分钟缓存

参考资料

使用 Hugo 构建
主题 StackJimmy 设计