更新时间:2023-02-27 03:12:48下载pdf
本文介绍了 Linux 版本的涂鸦智慧行业可视对讲门禁接入。
序号 | 术语 | 说明 |
---|---|---|
1 | cid | 三方设备 ID,设备的唯一编号 |
2 | sn | 下发 DP 点的唯一编号 |
3 | atop 接口 | 涂鸦对外提供的 HTTPS 接口 |
4 | 下发 | 云端指令通过 MQTT 消息通知给设备 |
5 | 上报 | 设备端消息通过 atop 接口或 MQTT 消息通知给云端 |
本文档仅支持直连设备的接入方式,即门禁设备内置 Tuya IPC SDK 的方式。
序号 | 功能点 | 说明 |
---|---|---|
1 | 设备配网 | 设备配网完成后,才能接收云端的指令,和云端进行交互 |
2 | 视频通话 | 包含发起呼叫、接听、挂断 |
3 | 人员操作 | 包括人员的新增、更新、移除、禁用、启用 |
4 | 人脸操作 | 包括人脸的新增、更新、移除 |
5 | 门禁卡操作 | 包括门禁卡的新增、更新、移除 |
6 | 二维码操作 | 包括二维码的新增、更新、移除 |
7 | 远程开门 | 用户通过涂鸦 App,下发开门指令给门禁设备,门禁设备收到开门指令后,打开门并上报通行记录 |
8 | 通行事件上报 | 门禁设备识别到有人通行,上报通行记录 |
9 | 评估人脸照片分数 | 服务端评估抓拍的人脸照片分数, 仅在前台登记客户时使用 |
10 | 动态刷新人员通行二维码 | 除支持下发的二维码通行以外, 增加了对动态可刷新二维码通行的支持 |
11 | 门禁通行密码操作 | 包括通行密码的新增、更新、移除 |
应用商店下载集智社区 App,通过集智社区 App 建立起和设备之间的音视频通话。
向涂鸦申请私钥,申请的私钥用来对配网信息进行解密。
您可以向涂鸦申请测试账号,并通过 二维码的生成地址 生成二维码。
设备扫描施工 App 二维码进行设备配网。二维码信息格式:
{
"t":"AYRfQ***",
"a":"a1-cn***",
"key":"1168***"
}
设备扫描二维码,并获取二维码的内容,根据二维码的内容调用 HTTPS 接口。具体调用方法如下:
请求 URL。
请求 URL 格式: https://%s/api.json?a=%s&v=%s&clientId=%s&lang=%s&t=%s&requestId=%s&sign= %s
完整 URL 示例: https://a1-cn.wgine.com/api.json?a=tuya.device.industry.base.edge.net.qrcode.query&v =1.0&clientId=mtn9nxykycwmknutmfky&lang=zh&t=1598010014&requestId=0928d339a d654fd1874b28d245948fc3&sign=d014ed4d192f60edd2d4ffeab545919bc3527ff4b0df2 6b4176ef1c0baed10cf
生成URL 参数。
a:apiName 默认:tuya.device.industry.base.edge.net.qrcode.query
v:version 默认:1.0
time 举例:1598010014 当前时间的 Long 类型
lang 默认:zh
clientId 默认:mtn9nxykycwmknutmfky
requestId 通过 UUID 生成,如:0928d3***
postData 说明:将扫描的二维码中的 key、cid 生成 JSON 字符串,格式为: {"t":15980***,"key":"a354fffa81674d8***","cid":"device164***"},再进行 md5 加密。该字符串通过 md5 加密后为:a1941a0237df3e***
sign 说明:将 a、v、time、lang、clientId、requestId、postData 先进行升序排序,排序后生成的字符串为: a=tuya.device.industry.base.edge.net.qrcode.query||clientId=mtn9nxykycwmknutmfky||l ang=zh||postData=a1941a0237df3e2e2e315c8dca27c0a1||requestId=0928d339ad654fd 1874b28d245948fc3||time=1598010014||v=1.0
然后将排序后的数据 a 通过 secret=wjx7ss3hww7xcpc7s4t3unxwfuw37w34(密钥)进行 hmacSha256 加密,加密后生成 sign 结果为:d014ed4d192f60edd2d4ffeab545919bc3527ff4b0df26b4176ef1c0baed10cf
生成 Http Body 参数.
返回数据示例。
{
"result": {
"data": "0e90f53c95772614c7a9be4b41f7130d764551a315f11d3bd04c7b50ac778f23d6e 6184f4a7e47d2fe58858c5019bc1086cb622855b7d0fad3491f0ee73bab21835bc67 ecbc04511321b0de51f63b3fc30d281c1a304244d0cefc59a976dbc830b11ef43785 204c16952edfa8eb6a7572cc8d8e49927f558f4dbd1086f3af5b33c8c998b4d84119 39bc78d2334aa633c49ba4f099cbbabc8a0de3e06f44a24c63d5ae167d985e70e19a 1bfedd44ddff1248b683c41c5b4733a8a9f201b85438b",
"key": "a354fffa816***"
},
"t": 159801***,
"success": true,
"status": "ok"
}
对 data 时间用 AES 进行解密,密钥为申请的私钥.解密后的数据示例。
{
"authKey": "BO3CzAHnqtbwyf4d6***",
"installLocation": "1 幢 1 单元***",
"vendor": "yufan***",
"pid": "toftl4za***",
"projectId": "11971***",
"uuid": "3aaa3***"
}
设备配网所需要的参数来自设备扫码,包含: t、pid、uuid、authKey 其中 t 来自二维码信息,有效期 10 分钟。
t、 pid、 uuid、authKey 在配⽹成功后,需要写⼊设备。确保设备重启、断电或恢复出厂设置后,还能重新获取上述数据,再次调用设备配网接口,从⽽连上云端;其中 t 在配网成功后不会过期。
具体配网实现参考 IPC SDK 开发手册及 Demo。
设备配网成功以后,调用该 atop 接口。仅需要在首次配网成功时调用,调用参数如下:
请求参数
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
cid | String | 门禁设备 ID | 是 |
deviceId | String | 涂鸦设备 ID | 是 |
uuid | String | 涂鸦 UUID | 是 |
projectId | String | 项目 ID | 是 |
productId | String | 产品 ID | 是 |
installLocation | String | 安装地址描述 | 是 |
vendorCode | String | 供应商 Code | 是 |
macAddress | String | 设备的 Mac 地址 | 是 |
extendData | String | 扩展属性 | 否 |
返回参数
类型 | 说明 |
---|---|
Boolean |
|
调用示例如下:
api_name: tuya.device.industry.base.edge.device.area.bind
api_version:1.0
message:
{
"input": "{\"cid\":\"device164***\",\"deviceId\":\"6c4363e795dcd4***\",\"installLocation\":\"1 幢 1 单元***\",\"productId\":\"toftl4za2q***\",\"projectId\":\"11971190533***\",\"uuid\":\"b893fa6d5***\",\"vendorCode\":\"yufan\",\"macAddress\":\"01:23:45:67:89:ab\"}"
}
result:
{
"result": {true},
"t": 159801***,
"success": true,
"status": "ok"
}
开启视频通话、接听、挂断时,调用该 atop 接口,调用参数如下:
请求参数
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
sn | String | SN 号,除呼叫以外,其它模式都需要设置;设置的值为呼叫时返回的 SN | 否 |
mode | String | 设备模式,如门铃: ac_doorbell | 是 |
type | String | 操作类型,见详细说明 | 是 |
deviceId | String | 涂鸦设备 ID | 是 |
targetAddress | String | 目标地址,格式:01-01-01-01-01-01,表示 01 小区 01 苑 01 幢 01 单元 01 层 01 号房间。没有传 00,比如没有苑,苑的位置传 00 | 是 |
extend | String | 通话后挂断返回 JSON 字符串:{“beginTime”:1592373736,“endTime”: 1593373736}
|
否 |
返回参数
类型 | 说明 |
---|---|
String | SN 号 |
targetAddress 传值说明
例:xx 小区 x 幢 x 单元 101
当设备作为单元门时:
目标地址三方自行解析为 00-00-00-00-01-01 格式,其中在满足该格式情况下,前 4 组的取值范围不影响单元门口机呼叫功能,默认补 00 即可,后 2 组根据现实呼叫情况可以从设备上输入,若呼叫 101 则需要传给云端 00-00-00-00-01-01。
前四组:00-00-00-00:不影响呼叫功能,默认补 00。
后二组:01-01:设备上输入真实的值。
当设备作为幢门时:
如上所述,解析为 00-00-00-01-01-01。
前三组:00-00-00:不影响呼叫功能,默认补 00。
后三组:01-01-01:设备上输入真实的值。
当设备作为小区门时:
如上所述,解析为 00-01-01-01-01-01。
前一组:00:不影响呼叫功能,默认补 00。
后五组:01-01-01-01-01:设备上输入真实的值。
操作类型详细说明
操作类型 | 场景 | 操作 |
---|---|---|
1 | 设备呼叫 App 和室内机 | 设备发送 type=1 事件 |
3 | 设备呼叫 App 和室内机,设备主动挂断,App 或室内机不操作 | 设备发送 type=3 事件,如果 App 已接听,需要传 extend |
4 | 设备呼叫 App 和室内机,App 或室内机未接听,呼叫时间超过设备限定,设备挂断。设备限定呼叫超时时间默认 30s | 设备发送 type=4 事件 |
5 | 设备呼叫 App 和室内机,App 或室内机接听后,App 或室内机挂断;sdk 会有回调事件给设备。 | 设备发送 type=5 事件,需要传 extend |
6 | 设备呼叫 App 和室内机,社区 App 或室内机接听.sdk 会有回调事件给设备。 | 设备发送 type=6 事件 |
7 | 设备呼叫 App 和室内机,App 或室内机接听后,通话时间超过设备限定,设备挂断;设备限定通话超时时间默认 90s。 | 设备发送 type=7 事件,需要传 extend |
调用示例如下:
api_name: tuya.device.industry.base.edge.control.protocol.send
api_version:1.0
message:
{
"input": "{\"deviceId\":\"6c8f87e58***\",\"mode\":\"ac_doorbell\",\"targetAddress\":\"00-00-00-00-01-01\",\"type\":\"1\"}"
}
result:
{
"result":"1208283103***",
"t": 1598010***,
"success": true
}
设备配网成功后,通过该 atop 接口查询设备同时支持 P2P 客户端的数量。
数量值作为 s_mgr_info.max_p2p_user 的值,以限制同时查看视频的客户端数量。
请求参数
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
deviceId | String | 涂鸦设备 ID | 是 |
返回参数
参数名 | 类型 | 说明 |
---|---|---|
maxClientNum | Integer | 最大同时支持 p2p 客户端的数量 |
deviceId | String | 涂鸦设备 ID |
调用示例如下:
api_name: tuya.device.industry.base.edge.device.p2p.client.num
api_version:1.0
message:
{
"input": "{\"deviceId\":\"6c8f87e58d***\"}"
}
result:
{
"result": {
"maxClientNum": 3,
"deviceId": "6c8f87e58d***"
},
"t": 160449***,
"success": true
}
对门禁抓拍的人脸照片进行评估,返回人脸照片分数。对抓拍的人脸照片进行评分,确认照片合格后,下发到其它门禁。
请求参数
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
fileId | String | 图片 ID,获取图片 ID 的接口 | 是 |
返回参数
参数名 | 类型 | 说明 |
---|---|---|
value | Double | 人脸评分阀值范围 0~10,8 分以上为识别成功 |
url | String | 人脸照片 URL |
调用示例如下:
api_name: tuya.device.industry.base.edge.ai.face.score
api_version:1.0
message:
{
"fileId": "45976fb2a6c06811e***"
}
result:
{
"result": {
"value": 10,
"url": "www.tuya.com/hello***.jpg"
},
"t": 16044***,
"success": true
}
请求参数
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
input | List<String> | 时间规则 ID 列表 | 是 |
返回参数
参数名 | 类型 | 说明 |
---|---|---|
ruleId | Float | 最大同时支持 P2P 客户端的数量 |
ruleName | String | 时间规则名称 |
period | String | 可通行时间周期,JSON 字符串,例如: [{“weekDay”:1,“weekTime”:[{“start”:“32400000”,“end”:“64800000”}]},{“weekDay”:2,“weekTime”:[{“start”:“684000000”,“end”:“75600000”}]}] |
allowedDate | String | 可通行时间段,JSON 字符串,例如:[{“start”:“1571587200000”,“end”:“1864569600000”},{“start”:“1573022801885”,“end”:“1864569600000”}] |
deniedDate | String | 不可通行时间段, JSON 字符串,例如: [{“start”:“1571587200000”,“end”:“1864569600000”},{“start”:“1573022801885”,“end”:“1864569600000”}] |
调用示例如下:
api_name: tuya.device.industry.base.edge.device.time.rules
api_version:1.0
message:
{
"input": ["242021***00000001","242021***00000002"]
}
result:
{
"result":[ {
"ruleId": "242021***00000001",
"ruleName": "时间规则 1",
"period": " [{\"weekDay\":1,\"weekTime\": [{\"start\":\"1571587200000\",\"end\":\"1864569600000\"},{\"start\":\"1864569600000\",\"end\":\"1864569700000\"}]}]",
"allowedDate": "[{\"start\":\"1571587200000\",\"end\":\"1864569600000\"}]",
"deniedDate": "[{\"start\":\"1571587200000\",\"end\":\"1864569600000\"}]",
}],
"t": 1604494202,
"success": true
}
时间段规则说明
period:可通行时间周期,可以指定在一周中哪些时间允许进行。
weekDay:用 1 到 7 分别表示周一到周日,开始时间、结束时间用距离 0 点相隔的毫秒数表示,比如 32400000 表明是 9 点
如 [{“weekDay”:1,“weekTime”:[{“start”:“32400000”,“end”:“64800000”}]},{“weekDay”:2,“weekTime”:[{“start”:“684000000”,“end”:“75600000”}]}] 表明的含义是 周一 9:00~18:00,周二 19:00~21:00 可通行,
allowedDate:可通行时间段,13 位时间戳表示
deniedDate:不可通行时间段,13 位时间戳表示
时间优先级:不可通行时间段 > 可通行时间段 > 可通行时间周期
先判断访问时间是否在“不可通行时间段”中,若在则不允许通行。否则看访问时间是否在“可通行时间段”中,若在则允许通行,若不在继续判断是否在“可通行时间周期”中,若在则允许通行,若都不在,则不能通行。
门禁识别到有用户通行时上报的记录,调用 MQTT 接口进行上报,上报参数如下:
请求参数
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 用户 ID,陌生人 UID 为空 | 是 |
t | long | 事件发生时间,时间的 long 类型 | 是 |
way | Integer | 开门方式:
|
是 |
imageId | String | 图片文件 ID,获取图片 ID 的接口 | 否 |
passPwd | String | 通行密码(密码通行方式下必传) | 否 |
cardNo | String | 卡号 | 否 |
temp | String | 体温 | 否 |
passType | Integer | 通行类型
|
否 |
location | String | 位置信息 | |
success | Integer | 是否成功
|
是 |
message | String | 消息提示(错误原因) | 否 |
返回参数
类型 | 说明 |
---|---|
boolean |
|
参考 IPC SDK 开发手册的 DP 点数据保存接口,上报 DP 点:126, DP 点数据格式示例:
{\"uid\":\"uid9527***\",\"imageId\":\"imageId\",\"t\":1598521***,\"success\":1,\"way\":4}
门禁调用 MQTT 接口主动上报告警事件,上报参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
alarmId | String | 告警 ID | 是 |
alarmType | Integer | 告警类型。
|
是 |
alarmCont | String | 告警值 | 是 |
imageId | String | 图片文件 ID,请参见 获取图片 ID 的接口 | 否 |
happenTime | Long | 告警发送时间 | 是 |
confirmEnable | Boolean | 处理状态。
|
否 |
extendData | String | 扩展信息 Json 类型 | 否 |
extendData Json字段说明
参数名 | 类型 | 说明 | 是否必传 |
---|---|---|---|
taggerType | Integer | 尾随者类型,告警类型为尾随类型时须传(alarmType=3 时须传)。
|
否 |
参考 IPC SDK 开发手册的 DP 点数据保存接口,上报 DP 点:185,DP 点数据格式示例:
{
\"deviceId\":\"12312***\",
\"alarmTime\": 1609435***,
\"alarmType\": 1,
\"alarmContent\": \"异常\",
\"dealTime\": 16094***,
\"alarmId\": \"123123***\",
\"extendData\": \"\"
}
上传图片来自于门禁设备识别到有用户通行的时候拍的照片。
调用 atop 接口获取,调用示例如下:
api_name: tuya.device.industry.base.edge.file.upload.token
api_version: 1.0
message: {"subjectType":"edgegateway_faceImg"}
result:
{
"result": {
"uploadUrl": "https://cetus-cn.wgine.com/v1.0/file/upload",
"token": "0f2bf5e20cf2cc99c73986c196b0d2c0"
},
"t": 1598010***,
"success": true,
"status": "ok"
}
发送 Https post 请求上传图片,https url 为 6.6.1 接口返回的 uploadUrl,6.6.1 接口返回的 token 放在 header 里面,header 的 key 为 file_upload_token,request body 里面放的是图片的字节流,上传的图片类型为 image/jpg。
上传示例:
response body 返回的结果:
{
"result": {"tmp_file_id": "45976fb2a6c06811ecc6a790ac562851***"},
"success": true,
}
其中 tmp_file_id 的值即为照片文件 ID。
每一个下发的 DP 点在设备端执行成功后,调用该 atop 接口,上报下发 DP 点的执行结果。
请求参数
参数名 | 类型 | 说明 | 是否必传 |
---|---|---|---|
sn | String | sn 号 | 是 |
success | Integer | 设备状态:
|
是 |
message | String | 执行结果描述 | 是 |
返回参数
类型 | 说明 |
---|---|
Boolean |
|
调用示例如下:
api_name: tuya.device.industry.base.edge.Issue.data.cmd.result.upload
api_version: 1.0
message: {"message": "执⾏成功","success": 1,"sn": 12082831037563***}
result: {
"result": {true},
"t": 159801061***,
"success": true,
"status": "ok"
}
人员通行权限校验步骤:
请求参数
参数名 | 类型 | 说明 | 是否必传 |
---|---|---|---|
uid | String | 用户 ID | 是 |
deviceId | String | 设备 ID | 是 |
verifyTypeList | List<Integer> | 验证类型列表
|
是 |
返回参数
参数名 | 类型 | 说明 |
---|---|---|
uid | String | 用户 ID |
extend | String | JSON 字符串,如{“healthCode”:“unknown”} |
extend 说明
验证类型 | extend | 描述 |
---|---|---|
1 | 返回 healthCode 字段 |
|
调用示例如下:
api_name: tuya.industry.base.edge.door.verify.pass
api_version:1.0
message:
{
"uid": "ay16110581781387***",
"deviceId": "6c2421a42631dcda68***",
"verifyTypeList": "[1]"
}
result:
{
"result": {
"uid": "ay16110581781387***",
"extend": "{\"healthCode\":\"unknown\"}"
},
"t": 16141671***,
"success": true
}
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
name | String | 涂鸦用户名 | 否 |
idCard | String | 证件 ID | 否 |
phone | String | 手机号 | 否 |
beginTime | Long | 有效期开始时间,13 位时间戳 | 否 |
endTime | Long | 有效期结束时间,13 位时间戳 | 否 |
ruleIdList | List |
时间规则 ID 列表 | 否 |
userFloor | Integer | 人员所在楼层,边缘侧呼梯时使用 | 否 |
secretKey | String | 用户秘钥,长度 32 位,建议 UUID 生成。App 端和设备端基于同一个秘钥生成动态二维码 | 否 |
refreshTime | Long | 二维码刷新时间,默认 5 分钟,单位毫秒 | 否 |
extend | String | 扩展信息,JSON 字符串 | 否 |
参考 IPC SDK 开发手册的 DP 点数据读取。下发的 DP 点:128。DP 点数据格式示例:
{
"t": 157355***,
"data": {
"cid": "1234***",
"dps": {
"128": {
"data": {
"beginTime": 1576846010886,
"endTime": 1576846010886,
"idCard": "idcard",
"name": "username",
"phone": "1778888***",
"uid": "123***",
"userFloor": 1,
"ruleIdList":["242021030300000001","242021030300000002"],
"secretKey":"fa26477e064d884c2fc13120e9da***",
"refreshTime": 300000
},
"mode": "dc_userInfo",
"sn": 120800586238851***,
"type": "add"
}
}
}
}
该接口需要支持幂等,即同一个 UID 人员新增成功后,还支持再次新增,再次新增时返回成功。
如果 beginTime 和 endTime 不为空,则人员有效期取 beginTime 和 endTime,否则以 timeRuleList 为准,timeRuleList 最大长度支持 3 条。获取到 ruleIdList 列表后,需要根据列表查询具体的时间规则列表,在人员通行的时候,需要根据时间规则校验用户是否可以通行。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
name | String | 用户名 | 否 |
idCard | String | 证件 ID | 否 |
phone | String | 手机号 | 否 |
beginTime | Long | 有效期开始时间,13 位时间戳 | 否 |
endTime | Long | 有效期结束时间,13 位时间戳 | 否 |
ruleIdList | List |
时间规则 ID 列表 | 否 |
userFloor | String | 人员所在楼层,边缘侧呼梯时使用 | 否 |
secretKey | String | 用户秘钥,长度 32 位,建议 UUID 生成;App 端和设备端基于同一个秘钥生成动态二维码 | 否 |
refreshTime | Long | 二维码刷新时间,默认 5 分钟,单位毫秒 | 否 |
extend | String | 扩展信息,JSON 字符串 | 否 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128 ,DP 点数据格式示例:
{
"t": 15735***,
"data": {
"cid": "1234***",
"dps": {
"128": {
"data": {
"beginTime": 1576846387411,
"endTime": 1576846387411,
"idCard": "idcard",
"name": "username",
"phone": "1778888***",
"uid": "uid***",
"userFloor": 1,
"secretKey":"fa26477e064d884c2fc13120e9da***",
"refreshTime": 300000
},
"mode": "dc_userInfo",
"sn": 120800744162785***,
"type": "update"
}
}
}
}
如果 beginTime 和 endTime 不为空,则人员有效期取 beginTime 和 endTime,否则以 timeRuleList 为准,timeRuleList 最大长度支持 3 条。获取到 ruleIdList 列表后,需要根据列表 查询具体的时间规则列表。
在人员通行的时候,需要根据时间规则校验用户是否可以通行。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128,DP 点数据格式示例:
{
"t": 1573557869,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"uid": "1231***"
},
"mode": "dc_userInfo",
"sn": 120801049576484***,
"type": "del"
}
}
}
}
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
enable | Integer | 启用/禁用
|
是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 157355***,
"data": {
"cid": "1234***",
"dps": {
"128": {
"data": {
"enabled": 1,
"uid": "uid"
},
"mode": "dc_userInfo",
"sn": 12080078984253***,
"type": "enable"
}
}
}
}
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
faceId | String | 人脸 ID | 是 |
url | String | 人脸照片地址 | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128;DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"faceId": "faceid",
"uid": "uid",
"url": "url"
},
"mode": "dc_faceInfo",
"sn": 1208011533364***,
"type": "add"
}
}
}
}
该接口需要支持幂等,即同一个 faceId 人脸照片新增成功后,还支持再次新增,再次新增时返回成功。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
faceId | String | 人脸 ID | 是 |
url | String | 人脸照片地址 | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"faceId": "faceid",
"uid": "uid",
"url": "url"
},
"mode": "dc_faceInfo",
"sn": 120801477101051***,
"type": "update"
}
}
}
}
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
faceId | String | 人脸 ID | 否 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"faceId": "faceid",
"uid": "uid"
},
"mode": "dc_faceInfo",
"sn": 120801517856684***,
"type": "del"
}
}
}
}
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
cardNo | String | 门禁卡号 | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"cardNo": "cardNo",
"uid": "uid"
},
"mode": "dn_cardInfo",
"sn": 12080165552296***,
"type": "add"
}
}
}
}
该接口需要支持幂等,即同一个 cardNo 卡新增成功后,还支持再次新增,再次新增时返回成功的结果。门禁须限制用户单个门禁卡,同个用户新增第二个门禁卡时,结果应返回失败。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
cardNo | String | 门禁卡号 | 是 |
oldCardNo | String | 被修改门禁卡号 | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"cardNo": "cardNo",
"oldCardNo": "oldCardNo",
"uid": "uid9***"
},
"mode": "dn_cardInfo",
"sn": 120801783846441***,
"type": "update"
}
}
}
}
用户限制单个门禁卡,更新门禁卡先清空该用户原先门禁卡,再新增。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
cardNo | String | 被删除门禁卡号 | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"cardNo": "uid9***",
"uid": "uid9***"
},
"mode": "dn_cardInfo",
"sn": 120801875624104***,
"type": "del"
}
}
}
}
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
enable | Boolean | 启用/禁用
|
是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 157355***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"uid": "uid9***",
"enable":true
},
"mode": "dn_cardInfo",
"sn": 120801875624104***,
"type": "enable"
}
}
}
}
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
qrCode | String | 二维码 Code | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"qrcode": "qrCode",
"uid": "uid9***"
},
"mode": "dc_qrCodeInfo",
"sn": 120802035040372***,
"type": "add"
}
}
}
}
该接口需要支持幂等,即同一个 qrCode 新增成功后,还支持再次新增,再次新增时返回成功。门禁须限制用户单个二维码,同个用户新增第二个二维码时,结果应返回失败。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
qrCode | String | 二维码 Code | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"qrcode": "qrCode",
"uid": "uid9***"
},
"mode": "dc_qrCodeInfo",
"sn": 120802035040372***,
"type": "update"
}
}
}
}
用户限制单个二维码,更新二维码先清空该用户原先二维码,再新增。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"uid": "uid9***"
},
"mode": "dc_qrCodeInfo",
"sn": 120802035040372***,
"type": "del"
}
}
}
}
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:127。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"127": {
"sn": 8839438***,
"uid": "uid9***"
}
}
}
}
远程开⻔不需要校验用户权限,即设备只要接收到 DP 点,就会进行开门操作,而不会校验人员信息。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
all | Boolean | 是否清空全量数据 | 否 |
person | Boolean | 是否清空人员数据 | 否 |
face | Boolean | 是否清空人脸数据 | 否 |
card | Boolean | 是否清空卡号数据 | 否 |
qrcode | Boolean | 是否清空二维码数据 | 否 |
passPwd | Boolean | 是否清空通行密码数据 | 否 |
other | Boolean | 是否清空其他数据 | 否 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:188。DP 点数据格式示例:
{
"t": 157355***,
"data": {
"cid": "12345***",
"dps": {
"188": {
"sn": 123***,
"all": false,
"person": true,
"face": true,
"card": false,
"qrcode": false,
"passPwd": false
}
}
}
}
一键清空设备数据,例如:人、人脸、卡及密码等信息。设备返厂维修或初始化设备场景下使用。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
timestamp | Long | 时间戳 | 否 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:187。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"187": {
"sn": 123***,
"timestamp": 1652698441227
}
}
}
}
设备时间同步,云端下发时间给设备,使设备时间与云端时间进行同步。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
sn | String | 请求唯一标识 | 是 |
bizType | String | 业务类型,默认值:maintain | 是 |
operateType | String | 操作类型,默认值:enable_disable_device | 是 |
extendData | String | JSON 字符串,如: {“value” :1},value,1: 启用,0: 禁⽤ | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:186;DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "123456***",
"dps": {
"186": {
"sn": 140550692870396***,
"bizType": "maintain",
"operateType": "enable_disable_device",
"extendData": "{\"value\":1}"
}
}
}
}
若禁用设备功能,则刷卡、密码、二维码、人脸、指纹、远程开门等功能不可用。
若启用设备功能,则刷卡、密码、二维码、人脸、指纹、远程开门等功能可用。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
passPwd | String | 门禁通行密码 | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"passPwd": "passPwd",
"uid": "uid9***"
},
"mode": "dc_passPwd",
"sn": 120802035040372***,
"type": "add"
}
}
}
}
用户支持多个通行密码,不同用户间通行密码允许相同。
该接口需要支持幂等,当同一个用户重复新增同一个通行密码时返回成功。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
passPwd | String | 门禁通行密码 | 是 |
oldPassPwd | String | 被修改的原门禁通行密码 | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"passPwd": "passPwd",
"oldPassPwd": "oldPassPwd",
"uid": "uid9***"
},
"mode": "dc_passPwd",
"sn": 120802035040372***,
"type": "update"
}
}
}
}
修改用户通行密码,如果用户下不存在被修改的通行密码(oldPassPwd),需返回失败。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
uid | String | 涂鸦用户 ID | 是 |
passPwd | String | 被删除的门禁通行密码 | 是 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:128。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"128": {
"data": {
"passPwd": "passPwd",
"uid": "uid9***"
},
"mode": "dc_passPwd",
"sn": 120802035040372***,
"type": "del"
}
}
}
}
移除用户通行密码,如果用户下不存在被删除的通行密码(passPwd
),需返回失败。
下发参数如下:
请求参数 | 参数类型 | 描述 | 是否必传 |
---|---|---|---|
type | Integer | 挂断类型。1 :全量 app 拒接,业务方主动挂断 |
是 |
mes | String | 挂断原因 | 否 |
参考 IPC SDK 开发手册的 DP 点数据读取,下发的 DP 点:191。DP 点数据格式示例:
{
"t": 1573557***,
"data": {
"cid": "12345***",
"dps": {
"191": {
"sn": 120802035040372***,
"type": 1,
"mes":"业务方主动挂断"
}
}
}
}
可视门禁收到挂断指令后,中断视频流传输。
标准 md5 算法参见: https://github.com/JieweiWei/md5
我们的 md5 算法在标准基础上做了封装,参见 md5Hex 方法。
#include <iostream>
#include "./md5.h"
using std::cout;
using std::endl;
string md5Hex(string data, bool isMd5){
string hex = "";
if (data != "") { //data != null
if (!isMd5) {
hex = MD5(data).toStr();
}
string midden = hex.substr(8, 16);
string temp = midden.substr(0, 8);
temp = temp + hex.substr(0, 8);
temp = temp + hex.substr(24, 8);
temp = temp + midden.substr(8, 8);
hex = temp;
}
return hex;
}
int main()
{
string data = "{\"t\":1598010***,\"key\":\"a354fffa81674d80b7d1e0696ad6***\",\"cid\":\"4rfvd80basdue7d***\"}";
cout<< md5Hex(data, false) <<endl;
return 0;
}
设备端需要支持两种二维码格式:
1.0 版本的二维码格式:
7421371370865597349888943036
2.0 版本的二维码格式:
{
"qrcode": "YXkxNjExMDU4MTc4MTM4N240Mjd8ZTRhZjIzZTY=" //value:Base64 编码后字符串
}
设备扫描二维码后的校验步骤:
根据二维码的内容判断二维码是 1.0 版本还是 2.0 版本;
如果是 1.0 版本,直接和人员的二维码进行比较,比较成功则允许通行;如果是 2.0 版本,则先通过 Base64 方法对内容进行解码,解析出二维码信息;
首先进行静态二维码对比校验,二维码信息和人员的二维码进行比较,比较成功则允许通行;
如果比对失败则通过动态二维码验证接口进行验证,验证成功则允许通行,验证失败则不允许通行。
动态二维码验证接口:
totp_util.c verifyTOTPFlexibility 方法校验动态二维码。
totp_util.h
#ifndef __TOTP_UTIL_H__
#define __TOTP_UTIL_H__
#ifdef __cplusplus
extern "C" {
#endif
//返回的 char*需要手动释放
char* generateTOTP(char* uid, char* secretKey,LONG_T refreshTime) ;
BOOL_T verifyTOTPFlexibility(char* uid, char* secretKey, char* willVerifyTotp, LONG_T refreshTime);
#ifdef __cplusplus
} // extern "C"
#endif
#endif
totp_util.c
#include "tuya_sha256.h"
#include "uni_time.h"
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <ctype.h>
#include "totp_util.h"
static long INITIAL_TIME = 0;
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
static void insert_zero(char* input);
static void hex_to_string(IN BYTE_T *input, IN INT_T input_len, OUT BYTE_T *output, INOUT INT_T* p_out_len);
static UINT64_T timeFactor(UINT64_T targetTime, UINT64_T refreshTime) ;
static char* doGenerateTOTP(char* key, char* time);
static unsigned char* hexStr2Bytes(char* src);
static void toUpperCase(char* input);
static void toUpperCase(char* input)
{
for(int i = 0 ;i<strlen(input);i++)
{
input[i]=toupper(input[i]);
}
}
//首部填充 0
static void insert_zero(char* input)
{
int size = strlen(input);
char* tmp = (char*)malloc(size+1) ;
strcpy(tmp,input);
int i=0;
for(;i <size;i++){
input[i+1]=tmp[i];
}
input[0]='0';
free(tmp);
}
static void hex_to_string(IN BYTE_T *input, IN INT_T input_len, OUT BYTE_T *output, INOUT INT_T* p_out_len)
{
INT_T i;
INT_T offset = 0;
if(NULL == input || NULL == output || NULL == p_out_len)
{
printf("invalid argument\r\n");
return;
}
if(*p_out_len < input_len * 2 + 1)
{
printf("OUTPUT LEN IS SHORT THAN INPUT LEN * 2\r\n");
*p_out_len = 0;
return;
}
for(i = 0;i < input_len;i++)
{
sprintf(&output[offset],"%02x",input[i]);
offset += 2;
}
output[offset] = 0;
*p_out_len = offset;
}
static char* longtoHexString(unsigned long input)
{
printf("long input=%lu \n",input);
char* str = (char*)malloc(10);
int i = 0;
unsigned long temp = 0;
while(input > 0 || i==0){
temp = input % 16;// 取余数
str[i++] = temp >= 10 ? ((temp - 10) + 'a') : (temp + '0');
input = input >> 4;
}
str[i] = '\0';
// 翻转 , 将高位与低位进行翻转
int t = 0;
for(int j = 0; j < i / 2; j++){
t = str[j];
str[j] = str[i - j - 1];
str[i - j - 1] = t;
}
printf("longtoHexString ouput=%lu \n",str);
return str;
}
static unsigned char* hexStr2Bytes(char* src)
{
unsigned char* tmp = (char*)malloc(strlen(src)+1);
memset(tmp,0,sizeof(tmp));
strcpy(tmp,src);
//保证 tmp 为偶数
if(strlen(tmp)%2 != 0){
insert_zero(tmp);
}
int m=0;
int len = strlen(tmp)/2;
char* end ;
unsigned char* dst = (char*)malloc(len+1);
memset(dst,0,len+1);
for(int i =0;i<len;i++)
{
m = i*2;
char subs[3]={0};
memcpy(subs,tmp+m,2);
dst[i]=strtol(subs,NULL,16);
}
free(tmp);
}
/**
* 获取动态因子
*
* @param targetTime 指定时间
* @param refreshTime 二维码刷新时间
* @return long
*/
static UINT64_T timeFactor(UINT64_T targetTime, UINT64_T refreshTime)
{
return (targetTime - INITIAL_TIME) / refreshTime;
}
/**
* @param key 用户 ID+种子密钥
* @param time 时间因子
* @return
*/
static char* doGenerateTOTP(char* key, char* time)
{
// 1、如果 time 小于 16 个字符,则用零补齐,例如:30B649C -> 00000000030B649C
int time_len = MAX(17,strlen(time));
char* fill_time=(char*)malloc(time_len);
memset(fill_time,0,time_len);
strcpy(fill_time,time);
while (strlen(fill_time) < 16) {
insert_zero(fill_time);
}
unsigned char* input = hexStr2Bytes(fill_time);
// 哈希加密
BYTE_T hash[32+1] = {0};
sha2_hmac(key,strlen(key),input,strlen(input),hash,0);
// 返回指定位数的动态口令
INT_T result_len = 65;
char* result = (char*)malloc(result_len);
memset(result,0,result_len);
hex_to_string(hash, strlen(hash), result, &result_len);
//如果返回值小于指定的位数,则用 0 补齐
while (strlen(result) < 8) {
insert_zero(result);
}
printf("sha2_hmac result:%s\n", result);
free(fill_time);
fill_time=NULL;
free(input);
input=NULL;
return result;
}
/**
* 刚性口令验证, 3 个周期内都能验证通过
*
* @param uid 用户 ID
* @param secretKey 秘钥,32 位字符串,建议 UUID 生成
* @param willVerifyTotp 待验证的二维码信息
* @param refreshTime 二维码刷新时间
* @return boolean
*/
BOOL_T verifyTOTPFlexibility(char* uid, char* secretKey, char* willVerifyTotp, LONG_T refreshTime)
{
if (!uid || !secretKey|| !willVerifyTotp ) {
printf("param err \r\n");
return false;
}
//获取当前时间 ms 级别
UINT64_T now = uni_time_get_posix_ms();
//uuid 和 secretKey 构造一个变量
char* uid_secretKey = (char*)malloc(strlen(uid)+strlen(secretKey)+1);
memset(uid_secretKey,0,sizeof(uid_secretKey));
strcpy(uid_secretKey,uid);
strcat(uid_secretKey,secretKey);
char* time1 = longtoHexString(timeFactor(now, refreshTime));
toUpperCase(time1);
//TOTP 加密 周期一
char* tempTotp1 = doGenerateTOTP(uid_secretKey, time1);
//相对返回 TRUE
if (strcmp(tempTotp1,willVerifyTotp)==0) {
free(tempTotp1);
free(uid_secretKey);
free(time1);
return TRUE;
}
free(tempTotp1);
//TOTP 加密 周期二
char* time2 = longtoHexString(timeFactor(now - refreshTime, refreshTime));
toUpperCase(time2);
//uuid 和 secretKey 构造一个变量
memset(uid_secretKey,0,sizeof(uid_secretKey));
strcpy(uid_secretKey,uid);
strcat(uid_secretKey,secretKey);
char* tempTotp2 = doGenerateTOTP(uid_secretKey, time2);
if (strcmp(tempTotp2,willVerifyTotp)==0) {
free(tempTotp2);
free(uid_secretKey);
free(time2);
return true;
}
free(tempTotp2);
//TOTP 加密 周期三
char* time3 = longtoHexString(timeFactor(now + refreshTime, refreshTime));
toUpperCase(time3);
memset(uid_secretKey,0,sizeof(uid_secretKey));
strcpy(uid_secretKey,uid);
strcat(uid_secretKey,secretKey);
char* tempTotp3 = doGenerateTOTP(uid_secretKey, time3);
if (strcmp(tempTotp3,willVerifyTotp)==0) {
free(tempTotp3);
free(uid_secretKey);
free(time3);
return true;
}
free(tempTotp3);
free(uid_secretKey);
free(time3);
return false;
}
/**
* 生成动态码
*
* @param uid 用户 ID
* @param secretKey 动态种子秘钥,32 位字符串,建议 UUID 生成
* @param refreshTime 二维码刷新时间
* @return
*/
char* generateTOTP(char* uid, char* secretKey,LONG_T refreshTime)
{
if (!uid || !secretKey || refreshTime==0) {
printf("param err \r\n");
return false;
}
// 获取当前时间的时间戳
UINT64_T now = uni_time_get_posix_ms();
// 将动态因子转为 16 进制
printf("cur time =%llu,",now);
printf("timeFactor%lu,",timeFactor(now, refreshTime));
char* time = longtoHexString(timeFactor(now, refreshTime));
toUpperCase(time);
char* uid_secretKey = (char*)malloc(strlen(uid)+strlen(secretKey)+1);
strcpy(uid_secretKey,uid);
strcat(uid_secretKey,secretKey);
char* totp = doGenerateTOTP(uid_secretKey, time);
free(uid_secretKey);
free(time);
return totp;
}
2.0 版二维码示例
二维码内容
{
"qrcode": "YXkxNjExMDU4MTc4MTM4N240Mjd8ZTRhZjIzZTY=" //value:Base64 编码后字符串
}
YXkxNjExMDU4MTc4MTM4N240Mjd8ZTRhZjIzZTY= Base64 解码后获得字符串
"ay16110581781387***|e4af23e6"
用户 ID: ay16110581781387***
二维码信息: e4af23e6
首先根据用户 ID 获取静态二维码进行对比。
如果对比失败,则进行动态二维码校验。
二维码刷新时间: 5 * 60 * 1000
根据用户 ID 查询到用户的秘钥 secretKey
然后调用动态二维码验证接口 TOTPUtils.verifyTOTPFlexibility
返回 true,校验通过。
门禁设备需支持读取门禁卡功能;人员卡号数据在门禁卡第 7 扇区,门禁从门禁卡第 7 扇区读取门禁卡后,与设备内人员门禁卡对比,若对比成功,则门禁刷卡成功。
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈