openharmony 软总线-设备发现流程
6.1 设备发现流程
6.1.1 Wi-Fi设备发现
6.1.1.1 Wi-Fi设备发现流程
Wi-Fi设备在出厂状态或者恢复出厂状态下,设备上电默认开启SoftAP模式,SoftAP的工作信道在1,6,11中随机选择,SoftAP的Beacon消息中携带的SSID element满足表3要求。当通用互联APP发起主动扫描Probe Request请求,此时设备如果收到Probe Request请求需要回复Probe Respone消息,Probe Respone消息中携带的SSID element也需要满足表3要求。如果设备长时间未进行被配网或点到点本地控操作,建议30分钟后关闭Beacon广播。
6.1.1.2 Wi-Fi设备发现字段
【适用范围】IF1.2 【描 述】SoftAP的Beacon消息和Probe Respone消息中携带的SSID element字段。
参数 | 名称 |
---|---|
SSID | 如下表 3:SSID格式 |
Hidden SSID | SSID不需要隐藏 |
BSSID | 设备的MAC地址 |
Channel | 工作信道在1, 6,11中随机选择 |
Security | 开放(Open) |
Beacon Interval | 100 TUs |
DTIM Interval | 无特殊要求 |
表2:Beacon要求
字段 | 长度(字节) | 说明 |
---|---|---|
Oh- | 3 | 固定前缀,作为设备识别的标识。 |
AA…AA | 长度之和≤14 | 企业英文名(可简写)。字符串可以由字母、数字或空格组成。例如HUAWEI。 |
BB…BB | 品类英文名(可简写)。字符串可以由字母、数字或空格组成。例如Smart TV或TV。 | |
-X | 2 | 设备识别的标识。其中,-为固定分割符;X为SoftAP版本号。 |
YYYYY | 5 | PID:产品标识 |
RRRR | 4 | 随机生成,避免出现设备重复 |
表3:SSID IE格式
6.1.2 BLE设备发现
6.1.2.1 BLE设备发现流程
BLE设备在出厂状态或者恢复出厂状态下,设备上电默认开启Advertising广播,广播类型为ADV IND。当通用互联APP发起主动扫描Scan Request请求,此时设备如果收到Scan Request请求需要回复Scan Respone消息,Scan Respone消息中携带的Ad Structure也需要满足6.1.2.2章节要求。
6.1.2.2 BLE设备发现字段
【适用范围】IF1.1 【描 述】蓝牙设备发送的广播包advertising和扫描响应scan response消息。
6.1.2.2.1 总体结构
蓝牙设备发送的广播包advertising和扫描响应scan response消息的Payload均包含AdvA、Data两部分,如下图所示。
AdvA:表示广播方的地址,即蓝牙设备的MAC地址,长度为6字节。 注意:MAC地址必须使用Public MAC,不得使用随机MAC。
Data:表示数据包,可以为AdvData(广播数据)或ScanRspData(扫描响应数据)。每个数据包均由有效数据(significant)和无效数据(non-significant)两部分组成,长度固定为31字节。
有效数据:包含若干个广播数据单元(即AD Structure),AD Structure的结构=Length+AD Type+AD data。
Length:表示该AD Structure数据的总长度,即为AD Type与AD Data的长度和(即不含Length字段本身的1字节)。
AD Type:表示该广播数据代表的含义,如设备名、UUID等。
AD Data:表示具体的数据内容。
无效数据:当有效数据长度不满31字节时,其余的用0补全。这部分的数据是无效的。
6.1.2.2.2 AD Structure1结构(Flags)
AD Structure1用于描述设备支持的BLE、BR等信息,其结构需要遵循蓝牙标准协议保持,长度为3个字节。
字段 | 长度(字节) | 取值 | 说明 |
---|---|---|---|
Length | 1字节 | 0x02 | 表示AD Type与AD Data的总长度。 |
AD Type | 1字节 | 0x01 | 表示该广播数据代表的含义。此处取值固定为0x01,对应的数据类型为Flags。 |
AD Data | 1字节 | 0x06 | 表示蓝牙设备的物理连接能力。对应Bit位的取值为1时,代表True;取值为0时,代表False。· bit0:LE受限可发现模式。· bit1:LE通用可发现模式。· bit2:不支持BR/EDR。· bit3:对Same Device Capable(控制器)同时支持BLE和BR/EDR。· bit4:对Same Device Capable(主机)同时支持BLE和BR/EDR。· bit5~7:预留。 |
在本规范中,不同类型的数据包的AD Structure1字段取值是一致的,固定为0x020106。
6.1.2.2.3 AD Structure2结构(Complete Local Name)
未注册到云端设备的前缀为“Oh-”,已注册到云端设备的前缀为“OH-”。已注册设备包含可选字段“MPP”。如果不携带MPP字段,则网关默认不回连该设备。
字段 | 长度(字节) | 值 | 是否必选 | 说明 | ||
---|---|---|---|---|---|---|
Length | 1 | 0xXX | 是 | AD Type与AD Data的总长度。 | ||
AD Type | 1 | 0x09 | 是 | 广播数据代表的含义,0x09表示蓝牙设备名称Complete Local Name。 | ||
AD Data | 未注册 | Oh- | 3 | 0x4F682D | 是 | 固定前缀,作为设备识别的标识。 |
AA…BB | ≤10 | 0xXX……XX | 自定义,由产品品牌名与设备名称组成。字符串可以由字母、数字、下划线组成,不支持其他字符。 | |||
-X | 2 | 0x2D31 | -为固定分割符;X为协议版本号,不能填0,默认填1。 | |||
YYYYY | 5 | 0xXXXXXXXXXX | PID:产品标识 | |||
NNNN | 4 | 0xXXXXXXXX | 设备序列号SN的后四位,用于区分同款产品的不同设备。字符串可以由字母、数字、下划线组成,不支持其他字符。 | |||
已注册 | OH- | 3 | 0x4F482D | 是 | 固定前缀,作为设备识别的标识。 | |
AA…BB | ≤10 | 0xXX……XX | 自定义,由产品品牌名与设备名称组成。字符串可以由字母、数字、下划线组成,不支持其他字符。 | |||
-X | 2 | 0x2D31 | -为固定分割符;X为协议版本号,不能填0,默认填1。 | |||
YYYYY | 5 | 0xXXXXXXXXXX | PID:产品标识 | |||
NNNN | 4 | 0xXXXXXXXX | 设备序列号SN的后四位,用于区分同款产品的不同设备。字符串可以由字母、数字、下划线组成,不支持其他字符。 | |||
M | 0.5 | 0xX | 否 | 可选字段,如果不携带MPP字段,则网关默认不回连该设备。· bit0:0-心跳广播报文,1-设备主动回连请求广播报文(例如设备有数据上报,需要连接网关)。· bit1:心跳间隔时长的单位。0-毫秒(ms),1-秒(s)。 | ||
PP | 1.5 | 0xXXX | 设备心跳间隔时长。数据类型为unsigned int,需转换为16进制。取值范围为20ms~3600s,如果小于20ms或大于3600s,分别按照20ms和3600s进行处理。 |
6.1.2.2.4 发送要求
设备名称广播报文按固定的时间间隔发送,单条广播的重发次数不低于5次。
对于功耗敏感设备(例如传感器、牙刷、水杯等):
当用户通过物理按键对设备机芯操作时,比如按牙刷按键、打开水杯盖、触碰传感器等场景,广播发送间隔推荐值为100ms。
当用户长时间无操作时,广播发送间隔取值范围为1s-60s,推荐值为30s。
对于非功耗敏感设备(有外接电源或电池容量较大的设备):广播发送间隔为200ms-2000ms,推荐取值1000ms。
6.2 安全协商流程
6.2.1 SPEKE协商流程图
• APP作为SPEKE协商的客户端启动SPEKE协商,传入PIN码;APP发送协商的请求到设备,其中消息携带了所支持的密钥协商的版本信息。
• 设备调用三方厂商的实现的接口,获取默认PIN码或预制PIN码;之后调用iot_connect SDK接口,启动SPEKE协商,传入PIN码。
• 设备侧集成的iot_connect SDK生成随机数salt,随机数challenge1,而后根据salt和PIN码生成设备侧的公私钥对pk1,sk1。
| salt=RND
secret=HKDF(PIN, salt, "ohos_connect_speke_base_info", 32B);
base=X25519.Hash2Point(secret)
sk1=RND
pk1=X25519.computeSharedSecret(sk1,base) |
---|
• 设备发送SPEKE协商的响应消息,携带设备侧支持的协商version、salt、challenge1、pk1(设备侧公钥)发送给APP。
• APP根据salt+PIN码生成APP侧的公私钥对pk2、sk2。
• APP侧根据设备侧的公钥pk1,自身的私钥sk2生成共享密钥SharedSecret(其原理就是DH密钥交换算法);然后使用SharedSecret和salt派生出SessionKey1(用于数据加密)和SessionKey2(用于挑战值hamc的计算);使用SessionKey2、challenge1、challenge2生成kcfData2;使用SessionKey1、salt生成真正用于加密的密钥DataEncKey。
| secret = HKDF(PIN, salt, "ohos_connect_speke_base_info", 32B);
base = X25519.Hash2Point(secret)
sk2 = RND
pk2 = X25519.computeSharedSecret(sk2,base)
SharedSecret = X25519.computeSharedSecret(sk2,pk1)
SessionKey1 || SessionKey2 = HKDF(Sharedsecret, salt, "ohos_connect_speke_sessionkey_info", 32B);
kcfData2 = HMAC(SessionKey2, challenge2||challenge1);
DataEncKey = HKDF(SessionKey1, salt, "ohos_connect_return_key", 16B); |
---|
• APP侧发送自身的pk2(APP侧公钥)、challenge2、kcfData2给到设备侧。
• 设备侧根据APP侧的公钥pk2、自身的私钥sk1生成共享密钥SharedSecret(其原理就是DH密钥交换算法);然后使用SharedSecret和salt派生出SessionKey1和SessionKey2;使用使用SessionKey2、challenge1、challenge2生成new_kcfData2,并且kcfData2验证;如果两者相等,则计算kcfData1,进一步求出使用SessionKey1、salt生成真正用于加密的密钥DataEncKey。
| SharedSecret=X25519.computeSharedSecret(sk1,pk2)
SessionKey1 || SessionKey2 = HKDF(SharedSecret, salt, "ohos_connect_speke_sessionkey_info", 32B);
new_kcfData2 = HMAC(SessionKey2, challenge2||challenge1);
new_kcfData2 ?= kcfData2
kcfData1 = HMAC(SessionKey2, challenge1||challenge2);
DataEncKey = HKDF(SessionKey1, salt, "ohos_connect_return_key", 16B); |
---|
• 设备侧发送SPEKE密钥协商结束的响应,携带kcfData1。
• APP侧使用SessionKey2、challenge1、challenge2生成new_kcfData1,并且kcfData1验证,验证通过然后结束SPEKE密钥协商。
new_kcfData1 = HMAC(SessionKey2, challenge1||challenge2); |
---|
new_kcfData1 ?= kcfData1 |
说明: 1.SessionKey1,SessionKey2和DataEncKey都是16B;
2.challenge1和challenge2是安全随机数,长度为16B,不能使用不安全的伪随机数,例如C语言的rand;
3.pk1和pk2是安全随机数,长度为32B;
4.HKDF采用mbedTLS库的mbedtls_hkdf;
5.HMAC采用HMAC_SHA_256。
6.2.2 SPEKE Over CoAP(Wi-Fi设备、以太网设备)
6.2.2.1 SPEKE协商开始请求消息
【描述】APP与设备首次配网或注册时需要在IP层进行SPEKE协商,单播报文。
【方向】配置器->生态设备
【请求】coap+udp://设备IP:5683/SPEKE
Header:
ver 0x01 //版本,固定值
type 0x00 //Confirmable, OHOS_COAP_MSG_TYPE_CON
tokenlen 0x08 //token长度,最大8字节
code 0x02 //0.02 POST
msgid 0x95CE //每次+1
Token: 0xAABBCCDDEEFF0011 //每次对话随机生成
Options:
0x0B SPEKE //OHOS_COAP_OPTION_TYPE_URI_PATH, SPEKE
0x0C 2 //OHOS_COAP_OPTION_TYPE_CONTENT_FORMAT, application/json
Body
{
"sessionId": "cee042fc402447199aa38354c272faba",
"puuid": "f645f5ee5329f2f317bac83f388e2818c628e249",
"authId": "6636343566356565353332396632663*",**
"authType": 1,
"cmd": "nego",
"securityData": {
"message": 1,
"payload": {
"version": {
"currentVersion": "1.0.0",
"minVersion": "1.0.0"
},
"operationCode": 6,
"support256mod": true
}
}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
puuid | 必选 | String(40) | 通用互联APP的唯一标识,可以由APP随机生成的UUID。APP登陆其它账号时,需要重新为该账号重启生成UUID。 |
authId | 必选 | String(80) | |
authType | 必选 | Integer | Auth类型 |
cmd | 必选 | String(8) | 协商命令类型 |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
Version | 必选 | Structure | 版本号信息 |
challenge | 必选 | String(32) | 应用终端安全随机数 |
salt | 必选 | String(32) | 应用终端随机盐值 |
epk | 必选 | String(512) | 应用终端公钥 |
version格式见下表:
version格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
currentVersion | 必选 | String(32) | 应用终端当前版本号 |
minVersion | 必选 | String(32) | 应用终端支持最小版本号 |
6.2.2.2 SPEKE协商开始返回消息
【描述】APP与设备首次配网或注册时需要在IP层进行SPEKE协商返回,单播报文。
【方向】配置器<-生态设备
【返回】
2.05
Header:
ver 0x01 //版本,固定值
type 0x02 //Ack, OHOS_COAP_MSG_TYPE_ACK
tokenlen 0x08 //token长度,最大8字节
code 0x45 //2.05 Response Content
msgid 0x95CE //与msg1中保持一致
Token: 0xAABBCCDDEEFF0011 //与msg1中保持一致
Options:
Body:
{
"sessionId": "cee042fc402447199aa38354c272faba",
"securityData": {
"message": 32769,
"payload": {
"version": {
"currentVersion": "1.0.0",
"minVersion": "1.0.0"
},
"challenge": "c0c6f07e0360fbd412535ddc428130e3",
"salt": "517d68aa92d6f8fd0779c1ddc339934c",
"epk": "eb7156dadcdc31c*"**
}
}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID,与请求报文一致。 |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
Version | 必选 | Structure | 版本号信息 |
challenge | 必选 | String(32) | 应用终端安全随机数 |
salt | 必选 | String(32) | 应用终端随机盐值 |
epk | 必选 | String(512) | 应用终端公钥 |
version格式见下表:
version格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
currentVersion | 必选 | String(32) | 应用终端当前版本号 |
minVersion | 必选 | String(32) | 应用终端支持最小版本号 |
6.2.2.3 SPEKE协商结束请求消息
【描述】APP跟设备首次配网或注册时需要在IP层进行SPEKE协商,单播报文。
【方向】配置器->生态设备
【请求】coap+udp://设备IP:5683/SPEKE
Header:
ver 0x01
type 0x00
tokenLen 0x08
code 0x02
msgid 0x95CE
protocol: 0
Token: AC7ED11B329540CE
Options:
0x0B SPEKE //URI “SPEKE”
0x0C 2 //Content-Format, application/json
Body:
{
"sessionId": "cee042fc402447199aa38354c272faba",
"puuid": "f645f5ee5329f2f317bac83f388e2818c628e249",
"cmd": "nego",
"securityData": {
"message": 2,
"payload": {
"challenge": "00e32ac4f5b4a9adc77ebb305b98aa0f",
"epk": "b022065e78a8f170e*",**
"kcfData": "7b1822756a6bb*"**
}
}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
puuid | 必选 | String(40) | 通用互联APP的唯一标识,可以由APP随机生成的UUID。APP登陆其它账号时,需要重新为该账号重启生成UUID。 |
cmd | 必选 | String(8) | 协商命令类型 |
securityData | 必选 | Structure | 安全协商请求数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 配网终端请求消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
challenge | 必选 | String(32) | 配网终端安全随机数 |
epk | 必选 | String(512) | 配网终端公钥 |
kcfData | 可选 | String(64) | 配网终端会话密钥HMAC,携带该字段时,需做key confirmation校验计算 |
6.2.2.4 SPEKE协商结束返回消息
【描述】APP与设备首次配网或注册时需要在IP层进行SPEKE协商返回,单播报文。
【方向】配置器<-生态设备
【返回】
Header: ver 0x01 //版本,固定值
type 0x02 //Ack, OHOS_COAP_MSG_TYPE_ACK
tokenlen 0x08 //token长度,最大8字节
code 0x45 //2.05 Response Content
msgid 0x95CE //与msg3中保持一致 Token: 0xAABBCCDDEEFF0022 //与msg3中保持一致
**Options: **
Body:
{
"sessionId": "cee042fc402447199aa38354c272faba",
"securityData": {
"message": 32770,
"payload": {
"kcfData": "a50618402de7f7bd08abc2*"**
}
}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 可选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
kcfData | 可选 | String(64) | 配网终端会话密钥HMAC,携带该字段时,需做key confirmation校验计算 |
6.2.2.5 SPEKE协商message定义
message | 取值 | 描述 |
---|---|---|
PAKE_REQUEST | 1 | 协商请求消息 |
PAKE_CLIENT_CONFIRM | 2 | 客户端确认消息 |
PAKE_RESPONSE | 32769 | 协商回应消息 |
PAKE_SERVER_CONFIRM | 32770 | 服务端确认消息 |
INFORM_MESSAGE | 32896 | 当异常发生时,使用这条消息通知对方 |
异常 | 错误码 | 描述 |
---|---|---|
FAILED | 0x00000001 | 操作失败 |
CONFLICT_REQUEST | 0x80000001 | 请求被拒绝 |
REQUEST_NOT_FOUND | 0x80000003 | 请求未找到 |
REQUEST_REJECTED | 0x80000005 | 请求被调用者拒绝 |
INVALID_PARAMETERS | 0xF0000001 | 非法参数 |
TIMEOUT | 0xF0000003 | 请求超时 |
UNSUPPORTED_VERSION | 0xF000000A | 版本与对端不对应 |
BAD_PAYLOAD | 0xF000000B | 接收的数据内容格式不符合预期 |
ALGORITHM_UNSUPPORTED | 0xF000000C | 算法不支持 |
PIN_ERROR | 0x0F000011 | PIN码错误 |
PEER_INVALID_PARAMETERS | 0xFF000001 | 对端参数异常 |
PEER_TIMEOUT | 0xFF000003 | 对方返回操作超时 |
PEER_BAD_PAYLOAD | 0xFF00000B | 对方操作返回解析数据异常 |
NOT_INIT | 0xFFFFFFFF | 未初始化 |
6.2.3 SPEKE Over BLE(BLE设备、Wi-Fi/BLE Combo设备)
BLE设备或Wi-Fi/BLE Combo的BLE辅助配网,由于BLE上无法直接承载CoAP,因此SPEKE协商消息与CoAP上有一定差异,本章将详细说明。BLE协议由于受限于BLE GATT报文MTU长度,需要进行分包,分包规则详见9.2.4章节。BLE GATT服务详见9.2.3章节。
6.2.3.1 SPEKE协商开始请求消息
【描述】APP与设备首次配网或注册时需要进行SPEKE协商,需要用BLE分包机制进行分包。
【方向】配置器->生态设备
【请求】
Service:
speke
Body:
{
"sessionId":"365ad1a8e2fd48a88f526e6798247514",
"puuid":"C545DB3CA52CD0B5",
"cmd":"nego",
"securityData":{
"requestId":"5311012805701433766",
"pakeData":"{
"message":64,
"supportedVersion":"1",
"groupAndModuleVersion":"2.0.16",
"groupOp":5}",
"dataLength":82
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
puuid | 必选 | String(40) | 通用互联APP的唯一标识,可以由APP随机生成的UUID。APP登陆其它账号时,需要重新为该账号重启生成UUID。 |
cmd | 必选 | String(80) | 协商命令类型 |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
Version | 必选 | Structure | 版本号信息 |
challenge | 必选 | String(32) | 应用终端安全随机数 |
salt | 必选 | String(32) | 应用终端随机盐值 |
epk | 必选 | String(512) | 应用终端公钥 |
version格式见下表:
version格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
currentVersion | 必选 | String(32) | 应用终端当前版本号 |
minVersion | 必选 | String(32) | 应用终端支持最小版本号 |
6.2.3.2 SPEKE协商开始返回消息
【方向】配置器<-生态设备
【回应】:
Service:
speke
Body:
{
"sessionId":"365ad1a8e2fd48a88f526e6798247514",
"securityData":{
"requestId":"5311012805701433766",
"pakeData":"{
"message":65,
"supportedVersion":"1",
"payload":"B8255619DD8A9BA0570DF837065C107EC17954D5AC2E8789B1FB975AAB74F5DB",
"salt":"99ECAC05E87984476FB446E10CB7EF76",
"epk":"W06LZEq1YbrV0LXvcj/JDXFqwbazXlRHqlIbwVKnlpvZUMKH25+eTfsCCVOsOL0mS4VbMmzZhwdkIbSqvD94ImMVabGOfs6JeLkbhbovNUqc8zaMMWPGKUWXaIDWyS7kL/7bGTvJY2raOx0PRh3WzWYKMOjXKqdhAWAX22OTqVUyAil3zsRxbqvm/G3nKGzdKM60JmKUJ3C57M+mELEOioDI8hMXgze9Hq2umkEvXBF4cP5RW4PVSUm5SfjDUYap8rh6oJHRWaDaH33nWcgueGQvWqU2K8m99Qu7QVRtRrSyk4pfEcaz+lHpHbRaRKMsu7NXm3T32QgMRkActmG8N7==",
"groupAndModuleVersion":"2.0.16",
"groupOp":5}",
"dataLength":555,
"errorCode":0}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID,与请求报文一致。 |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
Version | 必选 | Structure | 版本号信息 |
challenge | 必选 | String(32) | 应用终端安全随机数 |
salt | 必选 | String(32) | 应用终端随机盐值 |
epk | 必选 | String(512) | 应用终端公钥 |
version格式见下表:
version格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
currentVersion | 必选 | String(32) | 应用终端当前版本号 |
minVersion | 必选 | String(32) | 应用终端支持最小版本号 |
6.2.3.3 SPEKE协商结束请求接口
【描述】APP与设备首次配网或注册时需要进行SPEKE协商,需要用BLE分包机制进行分包。
【方向】配置器->生态设备
【请求】
Service:
speke
Body:
{
"sessionId":"365ad1a8e2fd48a88f526e6798247514",
"puuid":"C545DB3CA52CD0B5",
"cmd":"nego",
"securityData":{
"requestId":"5311012805701433766",
"pakeData":"{
"message":66,
"payload":"F36B32DC037A930ED84C44899BAC96BA0A8196ADA12677D5ECFB905472E2EC01",
"kcfData":"31252D75F8463D004B1CBCCC0FDB22585AA60C08C1D34D03AE593C1FF6D8233E",
"epk":"nFY91emAs0FcWxm4U5W4/NjpNhfOPJtDi2LlWYvQZ/dgt+01TLBkVUGAEvPpHNCK01nj4DJbL5cQnwcprPYibFiQlcKAQTATxXau/mG7/itIYSHzwgvmzte3WioxcuBdBVgUcQQr5FE6bHzJlFFBbP3bXGuM5Z9jnIvYXIG0UfeouOBcy2y1hbofjoPAuRoClo4TGDmYAFBeqbuF66L9ukgzTxGOEuQ3pvyfmd0VRWjP61boinHpNXVaUOwXo6MIFVYGzIGk3/CwuHFXtnV2XCxGHQfg/x1N3fzqthAglheifKUYQFlqBfQBUxtbRuRWzX+AOU4nj8EpCE5ji9qlYQ==",
"groupAndModuleVersion":"2.0.16",
"groupOp":5}",
"dataLength":566}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
puuid | 必选 | String(40) | 通用互联APP的唯一标识,可以由APP随机生成的UUID。APP登陆其它账号时,需要重新为该账号重启生成UUID。 |
securityData | 必选 | Structure | 安全协商请求数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 配网终端请求消息序列号 |
payload | 必选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
challenge | 必选 | String(32) | 配网终端安全随机数 |
epk | 必选 | String(512) | 配网终端公钥 |
kcfData | 可选 | String(64) | 配网终端会话密钥HMAC,携带该字段时,需做key confirmation校验计算 |
6.2.3.4 SPEKE协商结束返回消息
【方向】配置器<-生态设备
【回应】:
Service:
speke
Body:
{
"sessionId":"365ad1a8e2fd48a88f526e6798247514",
"securityData":{
"requestId":"5311012805701433766",
"pakeData":"{
"message":67,
"kcfData":"D34624A7415AE20367EFCF59692C6CA64FE2AF07BAFF1F0926D5419B4D0C6424""groupAndModuleVersion":"2.0.16",
"groupOp":5}",
"dataLength":137,
"errorCode":0}
}
Body参数说明见下表:
Body参数说明
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessionId | 必选 | String(32) | 安全会话标识ID |
securityData | 必选 | Structure | 安全协商响应数据信息,包括消息序列号、报文载荷 |
securityData格式见下表:
securityData格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
message | 必选 | Integer | 应用终端响应消息序列号 |
payload | 可选 | Structure | 有效载荷 |
payload格式见下表:
payload格式
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
kcfData | 可选 | String(64) | 配网终端会话密钥HMAC,携带该字段时,需做key confirmation校验计算 |
6.2.3.5 SPEKE协商message定义
message | 取值 | 描述 |
---|---|---|
PAKE_REQUEST | 64 | 协商请求消息 |
PAKE_CLIENT_CONFIRM | 65 | 客户端确认消息 |
PAKE_RESPONSE | 66 | 协商回应消息 |
PAKE_SERVER_CONFIRM | 67 | 服务端确认消息 |
INFORM_MESSAGE | 32896 | 当异常发生时,使用这条消息通知对方 |
6.3 设备认证流程
6.3.1 基于证书的设备认证
6.3.1.1 证书简介
证书可以实现离线认证,且安全性较高。对安全要求比较高的设备,宜采用证书方式。为了实现证书的互相认证,本文件采用多级CA证书颁发机制,各级CA都源自统一的根证书。采用四级证书链结构:根证书RCA->厂家证书VCA->产品证书PCA->设备证书DCA。
6.3.1.2 证书发放
CA认证中心用于为中间证书VCA进行授权或者交叉签名,不直接进行证书的颁发。厂商生成证书公私钥对,并在互联互通开发者平台上进行证书签名授权申请,授权申请通过以后,云平台会保存VID和VCA的对应关系。厂家采用自己的VCA签名生成PCA,并PCA证书添加到云平台,云平台会保存PID与PCA的对应关系。
图3 证书发放架构
1.2.1.3 证书有效性检验 设备证书的有效性检验可采用CRL或者OCSP的方式,由设备云平台所在的CA中心来维护。接入云平台可定期或在线从设备云所在的CA中心获取最新证书撤销列表信息。在进行设备合法性认证时,认证中心或认证代理根据证书撤销列表来判断该设备证书是否已被吊销。 云平台证书的撤销可采用CRL、OCSP或者短周期更新的方式,由云平台所在的CA中心来维护。这三种方式必须都支持,从而适配不同能力的设备。终端设备可根据自身的能力,选择对云平台证书撤销检测方式:如设备有较多的存储空间,可选择CRL的方式来存储云平台的证书撤销列表;如设备存储空间有限,但可连接互联网,则可采用OCSP的方式来获得云平台的证书撤销信息;如设备能力更低,则可采用短周期平台证书,在连接云平台时,不检测撤销信息,仅根据过期时间来判断。
6.3.1.4 证书格式与预置
证书格式采用X.509标准,详细的根证书、中间证书和设备证书格式定义参见附录。 云平台、厂家、生态设备应按下列规则预置证书: — 云平台:RCA证书,RCA私钥;VCA证书,PCA证书 — 厂 家:VCA证书,VCA私钥;PCA证书,PCA私钥;DCA证书,DCA私钥 — 设备预制:DCA证书,DCA私钥。
6.3.1.5 证书认证
生态设备接入云平台,云平台需要对设备进行认证。设备在认证请求时需要提供设备证书DCA,还需要提供设备证书签发的中间证书PID和VID,由云平台生成RCA/VCA/PCA的证书链,对设备进行验证。
6.3.2 基于预共享秘钥的设备认证
6.3.2.1 预共享密钥简介
生态设备预共享密钥为对称式凭证,实现简单,对设备要求低,适用于安全要求级别比较低的生态设备。
6.3.2.2 预共享密钥发放
生态设备预共享密钥由设备云生成,出厂时在生态设备侧进行预置。同时,设备云需保留生态设备PID、MAC与生态设备预共享密钥之间的对应关系。
6.3.2.3 预共享密钥格式与预制
生态设备预共享密钥生成方式由设备厂家自行确定,但密钥长度应不少于256bit。对于没有TEE和硬件根秘钥保护机制芯片,预共享秘钥需要通过HUKS导入进行加密存储。对于没有TEE和硬件根秘钥保护机制芯片,预共享秘钥需要通过HUKS导入进行加密存储
6.3.2.4 预共享密钥认证
生态设备预共享密钥存于设备云中。当生态设备接入云平台时,请求接入云,随后接入云与设备云建立接口,并进行设备预共享密钥认证。
6.4 配网注册流程
6.4.1 Wi-Fi设备配网注册
1.用户进入添加设备界面,APP触发Wi-Fi扫描,并将扫描到设备显示到APP界面,需要根据信号强度对设备进行排序;
2.用户点击连接设备,APP与设备进行SPEKE协商,根据设备SSID element确定设备SPEKE PIN来源;
3.APP获取设备certificate证书,生态设备返回证书;
4.APP将设备返回证书PID/VID/Certificate并向云端进行授权;
5.云根据设备上报的PID/VID生成RCA/VCA/PCA证书链,用证书链对设备Certificate进行验证,验证通过返回成功;
6.认证通过以后,向云端申请注册码,云判断设备已经认证通过,则返回注册码;
7.APP将注册码发送通过cloudsetup给设备;
8.设备根据cloudsetup,下发的Wi-Fi SSID和密码,连接路由器网络;
9.设备与端协商psk,协商成功后,生成对称加密秘钥;
10.设备到云端激活;
11.设备登录云端;
12.设备进行初始数据上报;
13.设备向云端获取authcode,基于authcode创建局域网本地控制接口。
6.4.2 BLE设备配网注册
TODO
6.4.3 以太设备配网注册
1.用户进入添加设备界面,APP触发CoAP扫描,并将扫描到设备显示到APP界面;
2.用户点击连接设备,APP与设备进行SPEKE协商;
3.APP获取设备certificate证书,设备返回证书;
4.APP将设备返回证书PID/VID/Certificate并向云端进行授权;
5.云根据设备上报的PID/VID生成RCA/VCA/PCA证书链,用证书链对设备Certificate进行验证,验证通过返回成功;
6.认证通过以后,向云端申请注册码,云判断设备已经认证通过,则返回注册码;
7.APP将注册码发送通过cloudsetup给设备;
8.设备根据cloudsetup保存psk;
9.设备与云端协商psk,协商成功后,生成对称加密秘钥;
10.设备到云端激活; 11.设备登录云端;
12.设备进行初始数据上报;
13.设备向云端获取authcode,基于authcode创建局域网本地控制接口。
6.4.4 Wi-Fi/BLE Combo设备配网注册
1.用户进入添加设备界面,APP触发CoAP扫描,并将扫描到设备显示到APP界面;
2.用户点击连接设备,APP与设备进行SPEKE协商;
3.APP获取设备certificate证书,设备返回证书;
4.APP将设备返回证书PID/VID/Certificate并向云端进行授权;
5.云根据设备上报的PID/VID生成RCA/VCA/PCA证书链,用证书链对设备Certificate进行验证,验证通过返回成功;
6.认证通过以后,向云端申请注册码,云判断设备已经认证通过,则返回注册码;
7.APP将注册码发送通过cloudsetup给设备;
8.设备根据cloudsetup保存psk;
9.设备与云端协商psk,协商成功后,生成对称加密秘钥;
10.设备到云端激活;
11.设备登录云端;
12.设备进行初始数据上报;
13.设备向云端获取authcode,基于authcode创建局域网本地控制接口。
7 通信安全
7.1 应用层加密
7.1.1 总体流程
应用层加密方案主要涉及几个步骤: 1、 双方协商随机数 2、 根据双方共享的PSK推导加密的密钥 3、 根据加密密钥加密报文的Payload 4、 继续根据密钥推导HMAC的secret,通过该secret计算报文的HMAC,并把固定长度MAC加在Payload的末尾,作为Payload的内容;用于保护报文不被篡改
7.1.2 PSK密钥推导算法
PBKDF2的算法需要结合SHA-256进行HASH计算,参考的OpenSSL接口如下: int PKCS5_PBKDF2_HMAC(const char *pass, int passlen, const unsigned char *salt, int saltlen, int iter, const EVP_MD *digest, int keylen, unsigned char *out); 其中salt为sn1(hex变为binary后为8 bytes)和sn2(hex变为binary后为8 bytes)的拼装,salt长度为16 bytes;digest为SHA-256;keylen为32 bytes。局域网本地控sn1和sn2通过IF1-APP-DEV接口进行协商;与云端通信时sn1和sn2通过IF2-DEV-WAN-PSK接口进行协商。蓝牙设备通过createSession接口进行协商。 瘦设备Device上PBKDF2的迭代次数为1次。
局域网本地控制(即LAN侧应用层加密)使用云下发的authcode计算摘要,使用此authcode计算PBKDF2;远程控制(即WAN侧应用层加密),云端为每个设备都分配了一个唯一的PSK,使用此PSK计算PBKDF2。
7.1.3 加解密
AES加密采用CBC模式,原始待加密的数据是通过PKCS5Padding的方式进行填充的。该算法全名为AES128-CBC-PKCS5Padding。
具体方法如下,原始数据必须补齐到16字节对齐,补齐的每个字节内容为补齐的长度。如: 一个字节的a补齐为:['a', 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F] 两个字节的a补齐为:['a', 'a', 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E, 0x0E]
AES-CBC加密时,需要两个密钥参数:Key和IV。这两个参数都是16 byte,刚好从上一步的PBKDF2的摘要中获取,摘要的前16 bytes用作AES的加密密钥Key;后16 bytes用作AES加密的IV值。。 OpenSSL的参考代码为: AES_KEY enc_key; AES_set_encrypt_key(key, key_len, &enc_key); AES_cbc_encrypt(padded_buf, enc_out, enc_len, &enc_key, ivec, AES_ENCRYPT);
openssl命令进行加密验证: root@wuhphis07722:/vdb/enkey# echo -n "helloworld" | openssl aes-128-cbc -K 451cd24c734b489b7c4b59090d3ba600 -iv f5b52ba4a6806a554388074a2bcc99f1 > enc.bin root@wuhphis07722:/vdb/enkey# xxd -ps enc.bin 78f4fb4634dc6f8b108e63eceb545055
openssl命令进行解密验证: root@wuhphis07722:/vdb/enkey# openssl enc -aes-128-cbc -in enc.bin -d -K 451cd24c734b489b7c4b59090d3ba600 -iv f5b52ba4a6806a554388074a2bcc99f1 | xxd 00000000: 6865 6c6c 6f77 6f72 6c64 helloworld
7.1.4 完整性保护
为了防止报文在传输过程中被篡改,需要保证报文的完整性。采用HMAC算法: HMAC(EVP_sha256(), secret, secret_len, input, input_len, mac, &ulMacLen); 需要输入secret对input进行MAC计算,采用SHA256哈希算法,算出的MAC长度为32 byte。
secret也是通过PBKDF2算法产生,其pass为第一步digest输出的32 byte前16 byte,salt仍然为sn1+sn2。
input的构造方法为:coap报文头+payload;计算出MAC后,追加在payload的末尾。 注意,coap over TCP时,coap头里的长度需要包括32 byte的MAC。
7.1.5 防重放机制
应用层加密使用COAP_OPT_SEQ_NUM_ID来表示每个请求的序号,在刚开始的会话握手过程中,通信双方各自产生一个随机的seq,后续每次发送报文时,必须在COAP_OPT_SEQ_NUM_ID Option中带上seq,且每次请求后seq都要加1;翻转后自动清零。 以下是SEQ_NUM交互过程中的变化逻辑示例:
7.2 通信安全
7.2.1 通用互联APP与云通信安全
通用互联APP与云端通信采用https方式,TLS的版本要≥v1.2,通用互联APP预制云端根证书,并对云端设备证书进行校验。
7.2.2 设备与云通信安全
设备与云通信接口,在设备资源受限时采用CoAP Over TCP,在资源不受限时采CoAP Over TLS。安全要求CoAP Over TLS采用传输层加密;CoAP Over TCP采用应用层加密。
8 通信接口
8.1 IF1接口 APP与设备通信接口
8.1.1 IF1-APP-DEV-DISCOVERY设备发现
Wi-Fi设备发现详见章节6.1.1:Wi-Fi设备发现。BLE设备发现详见章节6.1.2:BLE设备发现。以太网设备详见章节6.1.3:以太网设备发现。Wi-Fi/BLE Combo设备发现详见章节6.1.4:Wi-Fi/BLE Combo设备发现。
8.1.2 IF1-APP-DEV-SPEKE协商
Wi-Fi/以太网设备SPEKE协商详见章节6.2.2:SPEKE Over CoAP(Wi-Fi设备、以太网设备)。BLE设备和Wi-Fi/BLE Combo设备发现详见章节6.2.3:SPEKE Over BLE(BLE设备、Wi-Fi/BLE Combo设备)。
8.1.3 IF1-APP-DEV配网接口
Wi-Fi设备配网接口详见章节6.4.1,BLE设备配网接口详见章节6.4.2,以太网设备配网接口详见章节6.4.3,,Wi-Fi/BLE Combo设备配网接口详见章节6.4.4。
8.1.4 IF1-APP-DEV点到点本地控接口
点到点本地控接口详见。 APP和设备完整的激活过程参考设备与云端的握手及激活过程流程。其中,APP和设备的握手过程是通过发现设备的cloudSetup服务,并对设备进行云端激活,其交互过程如下图所示:
图1 APP和设备的握手过程示意图
如上所示,第一步搜索后,APP和Device之间会产生一个会话ID(sessId),以及两个随机数sn1和sn2,分别由APP和Device生成。后续APP和Device之间的报文交互都需要在CoAP报头中附带sessId,且CoAP报体都通过PBKDF2算法算出的密钥进行加密。具体安全相关的算法说明参考7.1 应用层加密。
瘦设备上电启动获取到IP地址后,如果发现自己还没有到云端激活,则自动处于待激活状态,对外提供cloudSetup服务;APP搜索这个服务时,设备可以返回,等待APP与设备建立会话sessId,并下发云端激活码;如果发现有已经注册过网关提供的homeCenter服务,则直接向网关注册,只维护与网关之间的会话sessId。 瘦设备至少要支持两个sessId,一个sessId用于向网关注册,并且维护心跳;另一个会话用于响应APP的搜索与激活。一旦与云端激活后,可以不回应此请求。
8.1.5 IF1-DEV-APP-DIS APP发现设备接口
【适用范围】IF1.2,IF1.3,IF5 【描述】APP通过组播的方式发现OpenHarmony设备;设备也可以通过组播方式发现其它OpenHarmony设备提供的服务 【请求】该请求发布给固定的组播地址:Broadcast IP**:5683**
GET /.well-known/core?st=ohCloudSetup
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
st | 可选 | String(40) | 待搜索的服务类型,提供了该服务的设备需要按照要求返回搜索结果。 |
【回应】:
{ "errcode": 0,
"devId": "2323-1221-...",
"devInfo": {
"sn": "00E0FC018008",
"model": "SmartSpeaker",
"devType": "004",
"manu": "002",
"prodId": "000b",
"hiv": "1.0",
"fwv": "10.01",
"hwv": "VER.C",
"swv": "V100R001C01B010",
"protType": 1
},
"services": [
{
"st": "light",
"sid": "light1"
},
{
"st": "ohCloudSetup",
"sid": "ohCloudSetup"
}
],
"sts": 1 // 默认0 , 0 不需要sts加密协商, 1 需要sts加密协商
}
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
devId | 必选 | String(40) | 设备ID,如果为空,表示设备还没有被绑定。 |
devInfo | 必选 | devInfoPublic | 设备公开的基本信息,参见链接内容 |
services | 必选 | serviceInfo[] | 该设备支持的OpenHarmony服务信息列表 |
sts | 可选 | 枚举 | 默认0 , 0 不需要sts加密协商, 1 需要sts加密协商 |
【错误码】: 无
8.1.6 IF1-DEV-SESS-ADD 设备会话创建接口
【适用范围】IF1-DEV,IF4
【描述】在调用Device的接口前,需要先通过此接口协商一个会话,通过协商出的会话进行操作。
【请求】
POST /.sys/sessMngr
{
"type": 1,
"modeSupport": 3,
"sn1": "2122232425262728",
"seq": 67
}
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
type | 必选 | Integer | Session会话的类型;OpenHarmony会话分为几种情况:1:匿名会话;通过OpenHarmony预置PSK创建的会话,无认证过程,需要限定使用场景。2:已配对设备的会话;已配对的OpenHarmony设备之间会产生相互信任的PSK,通过该PSK可以产生会话。 |
modeSupport | 必选 | Integer | APP支持的加密方式;必须把支持的模式或起来。当前APP要求支持AES以及DTLS加密方式,因此,需要设置为3。OpenHarmony报文加密的方式,支持以下几种方式:1:AES应用层加密方式2:DTLS加密方式 |
sn1 | 必选 | String(17) | 当协商出的modeResp为1时,需要使用应用层加密。加密的密钥使用PBKDF2算法协商,协商时APP侧需要产生随机数sn1,设备返回随机数sn2。sn1及sn2都是8 byte的随机数,在JSON报文传递时,都变成了16 byte的HEX字符串。 |
seq | 必选 | Integer | 本段的请求序列号,后续对端通过此会话发请求时,必须在COAP_OPT_SEQ_NUM_ID中带此seq数值,每个请求需递增此seq值。seq翻转后,继续从0开始。为了规避设备/网关侧JSON解析不支持大Unsigned Integer(超过0x7FFFFFFF)的问题,在初始协商时,随机生成的seq值不能超过0x7FFFFFFF;后续在OPTION中添加seq时,各设备都支持uint,可以强制转换成uint。 |
【回应】:
{
"errcode": 0,
"sessId": "232384789843",
"sn2": "2122232425262728",
"modeResp": 1,
"seq": 1
}
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
sessId | 可选 | String(16) | OpenHarmony会话应用层ID,握手后,后续所有的CoAP报文交互都需要在COAP_OPT_SESSION_ID Option中附带此ID。 |
modeResp | 必选 | Integer | Device选定的报文加密模式。 |
sn2 | 可选 | String(17) | 当modeResp为1时,应用层加密的Device侧随机数,用于应用层加密的握手协商。sn2为8 byte的随机数,在JSON报文传递时,变成了16 byte的HEX字符串。 |
dtlsPort | 可选 | Integer | 当modeResp为2时,设备采用DTLS的端口号。 |
seq | 必选 | Integer | 对端回应的序列号,后续给对端发请求时,必须在COAP_OPT_SEQ_NUM_ID中带此seq数值,每个请求需递增此seq值。seq翻转后,继续从0开始。为了规避设备/网关侧JSON解析不支持大Unsigned Integer(超过0x7FFFFFFF)的问题,在初始协商时,随机生成的seq值不能超过0x7FFFFFFF;后续在OPTION中添加seq时,各设备都支持uint,可以强制转换成uint。 |
【错误码】: OHOS_CONNECT_SESSION_DENY
8.1.7 IF1-DEV-APP-PROV2 APP为设备下发配网&注册信息
【适用范围】IF1 【描述】APP为设备下发配网&注册信息。 【请求】 POST /CloudSetup/v2 Speke({ "data": { "cloudUrl": "wh2iomplatform.hwcloudtest.cn", "code": "8Kjoruvj", "devId": "e83c4e7b-2158-4710-ad5d-7e1881f5f867", "password": "12345678", "psk": "65a71521277e1af38d8fa5f4ba185b0c", "ssid": "HUAWEI-9SEQLE ", "WifiBgnSwitch": 0 //0-不切换,默认bgn 1-autoswitch ** }** })
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
cloudUrl | 必选 | String(256) | 云url |
code | 必选 | String(40) | 注册码 |
devId | 必选 | String(40) | 设备的唯一ID |
psk | 必选 | String(40) | 预共享密钥 |
ssid | 可选 | String(32) | Wi-Fi AP的SSID |
password | 可选 | String(32) | Wi-Fi AP的密码 |
WifiBgnSwitch | 可选 | Integer | Wi-Fi AP的带宽 |
【回应】:
Speke({:
"errcode": 0,:
"lastStep": 100, //设备上一次添加失败错误码
"lastErr": 100 //设备上一次添加失败错误码
} )
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
errcode | 必选 | Integer | 0 成功 |
lastStep | 可选 | Integer | 设备上一次添加失败错误码 |
lastErr | 可选 | Integer | 设备上一次添加失败错误码 |
【错误码】:
8.1.8 IF1-DEV-APP-QRCode-PROV2 APP为设备通过二维码下发配网&注册信息
【适用范围】IF1
【描述】APP为设备通过二维码下发配网&注册信息。
【请求】
{ "u": "wh2iomplatform.hwcloudtest.cn", // cloudUrl
"c": "8Kjoruvj", // code
"d": "e83c4e7b-2158-4710-ad5d-7e1881f5f867", // devId
"p": "pnooFCk5mvStLKuu5aLkkQ==", //password,AES128,密钥通过预置PSK前面16字符进行加密
"k": "65a71521277e1af38d8fa5f4ba185b0c", // psk
"a": "HUAWEI-9SEQLE", // ssid
"w": 0 //0//0-不切换,默认bgn 1-autoswitch // WifiBgnSwitch,可选,默认是0
//二维码里面需要去掉空格,注释
}
8.1.9 IF1-DEV-APP-ONLINENOTIFY 设备配网成功的广播通知
【适用范围】IF1
【描述】设备在配网连接路由器WIFI成功后在IP层广播上报成功通知,连续发5次。
【请求】
POST /onlinenotify
{
"devId": "2323-1221-...", //设备id,Sha256(devId)
"sts": 1 // 默认0 , 0 不需要sts加密协商, 1 需要sts加密协商
}
8.2-8.4 (TODO)
8.5 IF5接口 APP与设备和设备与设备局域网本地接口
8.5.1 IF5-DEV-LOCAL-CTL APP本地控制智能设备
APP本地控制智能设备时,有三个阶段APP搜索周边的智能设备(已绑定且属于该账户的设备)、APP和智能设备进行握手协商、APP向智能设备下发控制命令。交互过程如下图所示:
图1 APP本地控制过程示意图
APP通过/.well-known/core?st=ohLocalControl搜索支持本地控制的智能设备;APP和智能设备进行会话协商;APP根据用户的控制动作向智能设备下发控制命令。本地控制特性使用UDP,端口为5686。 申请会话过程复用原有的“IF1-DEV-SESS-ADD 设备会话创建接口”;
控制命令的下发过程复用原有的“OHOS-CTRL-POST-API 设备控制接口”消息格式。只是在其中增加了字段,用于消息的去重以及维侧信息。下面是本地控制和控制命令的响应说明:
对于没有上报bridgeVersion字段,或者其版本号低于2的设备(详见2.6节),响应如下:
POST /{sid}
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
对于有上报bridgeVersion字段,且其版本号不低于2的设备,响应如下:
POST /{sid}
{
"subDeviceId": "2323-1221-...",
"subDeviceInfo": [
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
]
}
其中devId为被控设备的deviceId。
【回应】:
{
"errcode": 0,
"devId": "2323-1221-...",
"services": [
{
"sid": "sid1",
"reportId": "5753309600007",
"data": {
"characteristicName1": "value1",
"characteristicName2": "value2"
}
}
],
"devicedelay": 20
}
payload参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
devId | 必选 | String(40) | 被控制的设备ID。如果是桥下子设备的控制命令,则为对应子设备的设备ID。 |
services | 必选 | String | 服务及服务的状态 |
reportId | 可选 | String(16) | 数据标识,用于数据去重 |
取时间戳中去掉毫秒部分,然后与数据序号进行拼接。 | |||
devicedelay | 可选 | Integer | 设备侧控制命令执行时长(毫秒),用于维侧。 |
8.5.2 IF5-DEV-APP-LOCAL-DIS APP发现本地控制设备接口
【适用范围】IF1
【描述】APP通过组播的方式发现支持本地控制的OpenHarmony设备;
【请求】
该请求发布给固定的组播地址:Broadcast IP**:5686**
GET /.well-known/core?st=ohLocalControl
【回应】:
{
"errcode": 0,
"devId": "2323-1221-...",
"authCodeId": "658932612345",
"sessId": "232384789843",
"protocal": 0,
"bridgeVersion": "2"
}
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
devId | 必选 | String(40) | 设备ID,如果为空,表示设备还没有被绑定。 |
authCodeId | 必选 | String(32) | authCode以及authCodeId不定期更新。 |
sessId | 必选 | String(16) | 标识设备sdk当前协商的sessId,当apk发现此sessId不一致时需要重新协商。设备下电后该变量会清零。当手机侧发现sessId不一致时,需要重新和设备进行协商。 |
protocal | 必选 | Integer | 设备使用的json的版本号。 |
bridgeVersion | 可选 | Integer | 桥设备向APP上报本地控版本号,2及以上的版本支持桥下挂子设备的本地控制。非桥设备可不选。 |
【错误码】:
无
9 传输协议
9.1 CoAP协议
9.1.1 CoAP协议概述
CoAP协议支持CoAP over TLS,CoAP over TCP,CoAP over UDP的方式。生态设备应基于硬件性能、组网环境,选择对应的协议。点到点本地控和局域网本地控采用CoAP over UDP;连接云服务器采用CoAP over TLS,TLS协议应使用1.2及以上版本;性能受限设备可采用CoAP over TCP。
生态设备使用生态设备云服务平台的URL域名和传输协议的端口向云端发起连接请求,URL域名和端口信息在配网阶段动态下发给设备。
CoAP基于UDP承载时,受到链路层报文大小的限制,从而可能导致应用层一次所需传输的数据大于链路层的一次可以传递数据的大小,在该情况下,需进行分包处理。本文件中,定义CoAP的分包机制通过CoAP协议的标准块传输机制RFC7959来实现,应用层无需感知CoAP层的分包处理。
9.1.2 CoAP over TLS连接
基于COAP的信息获取命令示例:
请求:code=GET URI
应答:code=2.05 content
[BODY]
基于COAP的参数设置命令示例:
请求:code=POST URI
[BODY]
应答:code=2.05 content
[BODY]
如上所示,控制命令的基本格式为GET/POST+URI的方式;GET/POST定义是获取还是设置命令,URI标识具体的指令。CoAP层的返回码code都是2.05,具体的错误码在BODY中根据业务定义。CoAP参考规范:https://datatracker.ietf.org/doc/html/rfc7252 ;CoAP Over TLS和CoAP Over TCP参考规范:https://datatracker.ietf.org/doc/html/rfc8323。
9.1.3 CoAP over TCP连接
由于TCP协议不保障数据传输安全,应由CoAP应用层实现数据加密、完整性保护等数据传输安全机制。 设备使用服务端的URL域名、IP地址和端口向服务端发起TCP/UDP连接请求。建立TCP/UDP连接后,生态设备发送会话协商请求,协商CoAP应用层会话密钥。 在端云互联时,设备在调用CoAP会话协商接口后,必须及时调用注册或者登录接口(宜在2秒内),超时后CoAP会话失效,以防止对服务端的DDoS攻击。 CoAP应用层的加密通道建立应使用设备当前支持的密钥协商协议,具体协商协议见7.1章节。 基于COAP的信息获取命令示例:
请求:code=GET URI
应答:code=2.05 content
[BODY]
基于COAP的参数设置命令示例:
请求:code=POST URI
[BODY]
应答:code=2.05 content
[BODY]
如上所示,控制命令的基本格式为GET/POST+URI的方式;GET/POST定义是获取还是设置命令,URI标识具体的指令。CoAP层的返回码code都是2.05,具体的错误码在BODY中根据业务定义。CoAP参考规范:https://datatracker.ietf.org/doc/html/rfc7252;CoAP Over TLS和CoAP Over TCP参考规范:https://datatracker.ietf.org/doc/html/rfc8323。
9.1.4 CoAP over UDP连接
由于UDP协议不保障数据传输安全,应由CoAP应用层实现数据加密、完整性保护等数据传输安全机制。 设备使用服务端的URL域名、IP地址和端口向服务端发起TCP/UDP连接请求。建立TCP/UDP连接后,智能家居设备发送会话协商请求,协商CoAP应用层会话密钥。 在端云互联时,设备在调用CoAP会话协商接口后,必须及时调用注册或者登录接口(宜在2秒内),超时后CoAP会话失效,以防止对服务端的DDoS攻击。 CoAP应用层的加密通道建立应使用设备当前支持的密钥协商协议,具体协商协议见7.1章节。 基于COAP的信息获取命令示例:
请求:Type=Confirmable, code=GET URI
应答:code=2.05 content
[BODY]
基于COAP的参数设置命令示例:
请求:Type=Confirmable, code=POST URI
[BODY]
应答:code=2.05 content
[BODY]
如上所示,控制命令的基本格式为GET/POST+URI的方式;GET/POST定义是获取还是设置命令,URI标识具体的指令。CoAP层的返回码code都是2.05,具体的错误码在BODY中根据业务定义。CoAP参考规范:https://datatracker.ietf.org/doc/html/rfc7252
9.1.5 CoAP方法定义
本协议中支持CoAP的POST方法,均采用CON类型的消息。需支持的Option如下:
Uri-Path:定义接口类型。具体定义见下表。 Uri-Path定义
Uri-Path定义 | 备注 |
---|---|
/SPEKE | 用于speke协商 |
/CloudSetup/v2 | 用于下发设备配网信息 |
/.sys/psk | 用于psk协商 |
/.sys/activate | 用于设备激活 |
/.sys/login | 用于设备登录 |
/.sys/devInfoSync | 用于设备信息同步 |
/.sys/heartbeat | 用于心跳 |
/.sys/refresh | 用于psk刷新 |
/.sys/revoke | 用于设备向云端注销接口 |
/.sys/authCode | 用于下发authCode |
/.sys/diagnosis | 用于诊断信息上报 |
/.well-known/core?st=ohCloudSetup | 用于查询是否有待激活设备 |
/.well-known/core?st=ohLocalControl | 用于查询本地控制 |
Content-Format:如发送方支持JSON编码,则需携带该Option,取值为50(“application/json”)。
9.1.6 重传和容错
在CoAP over TLS或者CoAP over TCP下,重传和容错应通过传输层的重传机制保证,本文件不做规定。在CoAP over UDP下,局域网本地的重传和容错规定如下: 当两端建立IP层连接后,发送方进行第一条报文的发送,发送方将以100ms间隔发送第一条报文,直到收到接收方发送的响应报文。 对于中间报文,每隔1秒重发一次,一共发送5次。两端应对报文的重发做出冗余处理。 在发送最后一条报文时,为确保对端接收成功率,该条报文应发送5次,每次间隔100ms。
9.2 BLE传输
9.2.1 设备连接注册流程
设备连接注册流程主要分为以下三个阶段:
1. 建立连接: 主控设备与蓝牙设备之间使用OpenHarmony通用UUID,建立GATT连接。
2. 代理注册: 主控设备获取蓝牙设备的相关信息,并在云端代理注册。蓝牙设备接收并存储AuthCode,用于数据传输过程的加密。该过程主要涉及如下服务。
• 查询蓝牙辅助配网协议版本(netCfgVer)
• 查询设备配网注册信息(deviceInfo)
• 发送authCode至设备(authSetup)
1. 断开连接: 主控设备与蓝牙设备之间断开GATT连接。
9.2.2 设备控制流程
设备控制流程(含数据加解密)主要分为以下三个阶段:
1. 建立连接: 主控设备与蓝牙设备建立GATT连接。
2. 协商秘钥: 主控设备与蓝牙设备创建会话并协商秘钥(SN1、SN2),详见创建会话(createSession)。
3. 加密传输: 对于控制报文和响应报文,均需要经加密处理后再进行数据传输。传输结束后,断开GATT连接。
数据传输均需使用customSecData服务,典型场景包括:查询设备状态、查询设备所有服务、查询设备信息、控制设备状态、设备主动上报等。
9.2.3 BLE 服务要求
设备连接: 使用OpenHarmony通用UUID建立GATT连接。
OpenHarmony GATT服务声明为Primary Service,包含读、写两个属性,具体说明参见下表。
服务 Service ID | 服务UUID Service UUID | 属性 Characteristics | 属性UUID Characteristic UUID | 操作权限 Permissions | 数据类型Format |
---|---|---|---|---|---|
ConnectData | 15f1e600-a277-43fc-a484-dd39ef8a9100 | - | - | - | - |
- | - | readData | 15f1e601-a277-43fc-a484-dd39ef8a9100 | indicate/read | String |
- | - | writeData | 15f1e602-a277-43fc-a484-dd39ef8a9100 | write | String |
注意: 主控设备与蓝牙设备协商的MTU(Maximum Transmission Unit)范围为160~500字节, 默认协商的MTU为251字节。
设备配对: 推荐使用Just Works配对模式。
Just Works适用于无交互界面的蓝牙设备(例如蓝牙耳机),由主控设备发起连接即可完成配对,用户无需在被连接的蓝牙设备上进行操作。
设备控制: 已存在SIG Profile的设备(如血压计、血糖仪等):采用SIG Profile定义的设备能力。在设备发现、配对阶段,使用OpenHarmony通用UUID的GATT通道,设备注册完成后即断开连接。在设备控制阶段,使用SIG标准UUID建立连接。不存在SIG Profile的设备(如二轮车、点读笔等):优先采用OpenHarmony Profile定义的设备能力。在设备发现、配对、控制阶段,均使用OpenHarmony通用UUID的GATT通道。
9.2.4 数据传输及分包规范
蓝牙设备的数据在应用层传输时,需要遵循OpenHarmony通用的格式要求。数据包采用JSON字符串格式。每一数据包由Header与Payload组成,Header长度为7字节,Payload总长度为0~1500字节。单个数据包最大251字节,当数据包长度超过单包最大长度时,需要进行分包。
BLE数据包结构图
字段 | 长度(字节) | 是否必选 | 说明 | |
---|---|---|---|---|
Header | Version | 0.5 | 是 | 蓝牙BLE应用层协议的版本号,默认为0b0000。根据业务演进递增。 |
Cmd Type | 0.5 | 是 | 消息类型,包括:请求、响应、上报三种。· 0b0000:请求消息(REQ)。· 0b0001:响应消息(RSP)。· 0b0010:主动上报消息(RPT)。 | |
Messg ID | 1 | 是 | 消息序号,默认取值为0。· 0b00:表示该报文不需要分片。· 0x01~0xFF:表示该报文需要分片,取值与报文的token字段相同。 | |
Total Frame | 1 | 是 | 总包数。范围 0~255。· 0x01:不分包时,取值为1。· 0x02~0xFF:分包时,取值为≥2。 | |
Frame Seq | 1 | 是 | 包序号。· 0x00:不分包时取值为0。· 0x01~0xFF:分包时,取值为从1开始依次递增。 | |
Rev | 1 | 是 | 保留字段,便于后续扩展。当前可以设置为0。 | |
Encry | 1 | 是 | 数据加密方式。· 0x00:不加密。BLE需要SMP安全配对,配对建议采用Just works方式。· 0x01:配网SPEKE加密。· 0x02:控制SPEKE加密。· 0x03:Session Key加密。· 0x04:基于AuthCode派生秘钥加密。 | |
Return | 1 | 是 | 消息的执行结果。· 主动上报消息:填写0x00。· 请求消息:填写0x00。· 响应消息:填写执行结果。0x00表示执行成功,0x01表示执行失败。 | |
Payload | Data Format | 0.5 | 是 | 数据格式。当前只支持JSON字符串格式,取值固定为0b01。 |
Opt Type | 0.5 | 是 | 操作类型,取值说明如下:· 00:PUT· 01:GET· 02:REPORT | |
Service Length | 1 | 是 | 服务名长度。 | |
Service Name | n | 是 | 服务名称,ASCII字符,例如netCfgVer:查询蓝牙辅助配网协议版本 deviceInfo:查询设备配网注册信息 createSession:创建会话 authSetup:发送authCode至设备 customSecData:设备操作数据 authdelete:代理删除设备 clearDevRegInfo:恢复出厂设置 speke: SPEKE安全协商 filetrans: 文件传输 | |
Body Length | 2 | 是 | 数据长度。 | |
Body | N | 是 | json格式的数据内容,例如:{"sn": "0EFEEFFAEF","pid": "1234"} |
9.2.5 通用服务规范
9.2.5.1 查询蓝牙辅助配网协议版本(netCfgVer)
功能说明:建立GATT连接后,主控设备会通过netCfgVer服务,查询蓝牙辅助配网协议版本。蓝牙设备收到请求后,返回协议版本。 加密方式:不加密 请求格式: 当请求为空时,表示主控设备为手机。 当请求格式如下时,表示主控设备为网关。 {"source":"gw"} 响应格式: {"ver":%d}
参数 | 类型 | 说明 |
---|---|---|
ver | int | 蓝牙辅助配网协议版本,取值如下:3: 控制采用Speke加密,默认支持设备与手机直连。4: 协商采用Speke方式,控制采用Authcode加密。5:协商采用Authcode,控制采用Authcode加密。既支持设备与手机直连,又支持设备与网关连接。100~199:采用本协议规范接入,默认为100。 |
9.2.5.2 查询设备配网注册信息(deviceInfo)
功能说明:在设备代理注册之前,主控设备会通过deviceInfo服务,查询蓝牙设备的配网注册信息。蓝牙设备收到请求后,返回注册信息。
加密方式:基于AuthCode派生秘钥
请求格式:无
响应格式:
{
"productId":"%s", "sn":"%s", "vendor":[{ "devId":"%s", "deviceInfo":"%s"}]
}
其中,deviceInfo取值格式如下:
Comb设备:
** {"sn":"%s","model":"%s","devType":"%s","manu":"%s","prodId":"%s","mac":"%s","blemac":"%s","hiv":"%s","fwv":"%s","hwv":"%s","swv":"%s","protType":"%s"}
纯BLE设备:
{"sn":"%s","model":"%s","devType":"%s","manu":"%s","prodId":"%s","blemac":"%s", "hiv":"%s","fwv":"%s","hwv":"%s","swv":"%s","protType":"%s","longcon":"1"}**
参数 | 类型 | 说明 | ||
---|---|---|---|---|
productId | - | - | String | 产品ProdID,与Device Partner平台的取值保持一致。 |
sn | - | - | String | 设备SN号。 |
vendor | - | - | String | - |
devId | - | String | 设备ID。 | |
deviceInfo | - | String | - | |
sn | String | 设备SN号。 | ||
model | String | 设备型号。 | ||
devType | String | 设备类型。 | ||
manu | String | 企业名称。 | ||
prodId | String | 产品ProdID,与Device Partner平台的取值保持一致。 | ||
mac | String | Wi-Fi设备MAC地址,仅Comb设备涉及。 | ||
blemac | String | 蓝牙设备的MAC地址。 | ||
hiv | String | HarmonyConnect版本号。 | ||
fwv | String | 固件版本号。 | ||
hwv | String | 硬件版本号。 | ||
swv | String | 软件版本号。 | ||
protType | String | 协议类型。默认取值为4,表示蓝牙BLE连接协议。如果门锁支持BLE+Wi-Fi,则取值为12。0:未定义 1:Wi-Fi 2:Z-Wave 3:ZigBee 4:BlueTooth 5:PLC 6:BLE Mesh 7:NFC 8:Ethernet (以太网) 9:Moblie Network(3G/4G等无线接入设备) 10:USB 11:PLC+Wi-Fi(Wi-Fi用于升级) 12:BLE+Wi-Fi(Wi-Fi用于升级) 13:HiBeacon协议(设备通过蓝牙广播方式完成状态上报) |
9.2.5.3 发送authCode至设备(authSetup)
功能说明: 蓝牙设备注册成功后,主控设备会从云端获取authCode、并通过authSetup服务将authCode下发至蓝牙设备。蓝牙设备需要存储该值,用于后续数据传输的加解密。 加密方式: 不加密
发送格式: {
"devId":"xxxx",
"authCode":"xxxx",
"uidHash":"xxxx",
"authCodeId":"xxxx"
}
其中,authCode的长度为32字节,由16bytes的二进制数据转成16进制字符串而成。
9.2.5.4 创建会话(createSession)
功能说明: 主控设备通过createSession服务,请求创建会话并协商会话秘钥。蓝牙设备返回响应,会话创建成功。 加密方式: 不加密
请求格式:
{
"seq":%s,
"uuid":"%s",
"uidHash":"%s",
"sn1":"%s"
}
参数 | 类型 | 说明 |
---|---|---|
seq | String | 连接序列号,每次递增。 |
uuid | String | 手机的唯一标识。 |
uidHash | String | UID的Hash值。 |
sn1 | String | 协商的sn1参数,用于计算秘钥盐值。 |
响应格式:
{
"seq":%s ,
"sessId":"%s",
"sn2":"%s"** ,**
"authCodeId":"%s"
}
参数 | 类型 | 说明 |
---|---|---|
seq | String | 连接序列号,每次递增。 |
sessId | String | 设备分配给手机的会话ID,长度为32个字节的随机字符串。 |
sn2 | String | 协商的sn2参数,用于计算秘钥盐值。 |
authCodeId | String | 采用的authCode序号。 |
9.2.5.5 查询设备状态(customSecData)
功能说明: 主控设备通过customSecData服务,查询设备状态(携带具体sid)。蓝牙设备收到请求后,返回查询结果或错误码。 加密方式: spekeKey/sessionKey 请求格式:
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"onoff"}]
}
响应格式:
执行成功,返回具体查询结果。
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"onoff",
"data":{"onoff":0}
}]
}
执行失败,返回错误码。
{"errcode": xxx}
9.2.5.6 查询设备所有服务(customSecData)
功能说明: 主控设备通过customSecData服务,查询设备所有服务状态(sid为allservices)。蓝牙设备收到请求后,返回是否查询成功。查询成功后,蓝牙设备还需要主动上报所有服务状态,参见设备主动上报(customSecData)。 加密方式: spekeKey/sessionKey 请求示例:
{ "seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"allservices"}]
}
响应示例:
执行成功,返回0。
{"errcode": 0}
设备侧主动上报所查询的所有服务状态。
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"onoff",
"data":{"onoff":0}
},{
"sid":"brushstregth",
"data":{"brushstregth":1}
}]
}
执行失败,返回错误码。
{"errcode": xxx}
9.2.5.7 查询设备信息(customSecData)
功能说明: 主控设备通过customSecData服务,查询设备信息。蓝牙设备收到请求后,返回是否查询成功。查询成功后,蓝牙设备还需要主动上报设备版本号信息,参见设备主动上报(customSecData)。 加密方式: spekeKey/sessionKey 请求示例:
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"deviceinfo",
"source":"gw"** // 如果source字段取值为"gw",表明主控设备为网关;如果不携带该字段,表示主控设备为手机。
}]
}
响应示例:
执行成功,返回0。
{"errcode": 0}**
设备侧主动上报所查询的设备信息。
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"deviceinfo",
"data":[{
"hiv":"1.0", // 可选,HarmonyConnect版本号
"fwv":"1.0", // 必选,固件版本号
"hwv":"1.0", // 必选,硬件版本号
"swv":"1.0", // 可选,软件版本号
}]
}]
}
执行失败,返回错误码。
{"errcode": xxx}
9.2.5.8 控制设备状态(customSecData)
主控设备通过customSecData服务,发送设备状态控制指令。蓝牙设备收到请求后,返回是否执行成功。 操作执行成功后,蓝牙设备还需要主动上报最新的状态,参见设备主动上报(customSecData)。
加密方式: spekeKey/sessionKey
请求示例:
{
"seq":xxxx**,// xxxx为递增数字**
"vendor":[{
"sid":"onoff",
"data":{"onoff":0**}**
},{
"sid":"brushstregth",
"data":{"brushstregth":1**}**
}]
}
响应示例:
执行成功,返回0。
{"errcode": 0}
执行失败,返回错误码。
{"errcode": xxx}
9.2.5.9 设备主动上报(customSecData)
当蓝牙设备的状态发生变化(例如用户执行了设备控制操作)时,需要通过customSecData服务主动上报最新的状态。主动设备会根据最新的状态刷新设备状态。
说明
vendor中各字段的取值必须与OpenHarmony Profile保持一致。
加密方式: spekeKey/sessionKey
消息示例:
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"onoff",
"data":{"onoff":0}
},{
"sid":"brushstregth",
"data":{"brushstregth":1}
}]
}
9.2.5.10 代理删除设备(authdelete)
蓝牙设备在同一时间段只能与一个用户仅绑定。通过authdelete服务,解除蓝牙设备与老用户的绑定关系后,才能与新用户进行绑定。
加密方式: 无
请求格式:
{"challenge": "xxxx"}
响应格式:
执行成功,返回sigvalue取值。
{"sigvalue": "xxxx"} 其中,设备签名参数sigvalue的计算方法如下:
根据prk与info,计算okm的取值。
prk = extract(authcode)
info ="Device-Revoke"
okm= expand(prk, info)
采用hmac-sha256算法,计算签名参数。
sigvalue = hmac(devId+challenge+authcodeId, okm)
其中,authcode、devId、authcodeId在设备注册时均存储在Flash中。devid、challenge、authcodeId以及okm,均使用字面字符的直接byte[]、无需转为原始字节数组byte[],String到byte数组的转换统一按UTF-8处理。 执行失败,返回错误码。
{"errcode": xxx}
9.2.5.11 恢复出厂设置(clearDevRegInfo)
主控设备通过clearDevRegInfo服务,发送恢复出厂设置指令。蓝牙设备收到请求后,清除设备已注册的信息。 注意 在清除设备配网参数时,需要保留Authcode参数。其他用户执行代理删除操作时需要使用该参数。
加密方式: 基于Authcode派生秘钥
请求格式:
{"devId":"%s"}
参数 | 类型 | 说明 |
---|---|---|
devId | String | 设备注册成功后,云端分配给设备的唯一标识。 |
**表7 **参数说明 |
响应格式: 成功,返回0。 {"errcode":"0"} 失败,返回错误码。 {"errcode":"xxxx"}
9.2.5.12 SPEKE安全协商(speke)
蓝牙SPEKE安全协商,详见6.2.3章节。
9.2.5.13 文件传输(filetrans)
主控设备通过filetrans服务,进行文件传输,详细文件传输报文参见8.2.12章节。
9.2.5.14 通用错误码
蓝牙设备需要将指令是否执行成功,通过errcode字段返回给主控设备。errcode取值参见下表。
错误码 | 说明 |
---|---|
0 | 成功。 |
500 | 设备被重置。 |
600 | 设备控制失败。 |
601 | 状态查询失败。 |
602 | 内存不足。 |
603 | 设备异常。 |
604 | BLE协议栈异常。 |
10 数据模型
数据模型定义了生态设备与生态设备,APP与设备,设备与云平台之间交互需要遵循的规范。详细内容请参考《鸿蒙生态设备互联互通互操作 物模型规范》。
11 设备控制和设备管理
11.1 通用设备控制接口
11.1.1 OHOS-CTRL-GET-API
【适用范围】所有
【描述】对设备上的服务发送实时GET操作都如本文的接口定义。
【请求】
IF1及IF5 App ->Device接口请求示例:
GET /{sid}
CoAP点对点操作时,直接通过服务ID对服务进行操作。
IF2 Cloud->Device接口请求示例:
GET /{sid}
COAP_OPT_REQ_ID: requestId
COAP_OPT_USER_ID: userId
COAP_OPT_DEV_ID: devId
云端发给Device的请求在COAP_OPT_REQ_ID扩展Option中附带requestId,标识该请求的唯一ID;Device回应时,需要原封不动的回应此Option值。
云端发给Device的请求在COAP_OPT_USER_ID扩展Option中附带userId,标识哪个用户发起的请求;Device回应时,也需要原封不动的回应此Option值。
云端发给Device的请求在COAP_OPT_DEV_ID扩展Option中附带devId,标识发给哪个设备的请求;Device回应时,也需要原封不动的回应此Option值。
设备上不应该理解上述三个Option值的格式及内容,只需要原封不动的返回即可。
IF3 APP-Cloud接口请求示例: GET /userApp/v1/devices/{devId}/services/{sid} HTTP/1.1
需增加Authorization报头。
【回应】:
IF1及IF5 App<-Device接口返回示例:
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
IF2 Cloud<-Device接口返回示例:
COAP_OPT_REQ_ID: requestId [CoAP TCP设备需回应此报头]
COAP_OPT_USER_ID: userId [CoAP TCP设备需回应此报头]
COAP_OPT_DEV_ID: devId [CoAP TCP需回应此报头]
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
对于IF1、IF5、IF2请求的回应,需要进行AES加密。
【错误码】:
如果设备不在线,返回OHOS_CONNECT_DEV_OFFLINE;
如果设备响应超时,返回OHOS_CONNECT_DEV_TIMEOUT。
11.1.2 OHOS-CTRL-POST-API
【适用范围】所有
【描述】对设备上的服务发送实时POST操作都如本文的接口定义。
【请求】
IF1及IF5 App ->Device接口请求示例:
POST /{sid}
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
CoAP点对点操作时,直接通过服务ID对服务进行操作。
IF2 Cloud->Device接口请求示例:
POST /{sid}
COAP_OPT_REQ_ID: requestId
COAP_OPT_USER_ID: userId
COAP_OPT_DEV_ID: devId
{
"characteristicName1": "value1",
"characteristicName2": "value2"
} 云端发给Device的请求在COAP_OPT_REQ_ID扩展Option中附带requestId,标识该请求的唯一ID;Device回应时,需要原封不动的回应此Option值。
云端发给Device的请求在COAP_OPT_USER_ID扩展Option中附带requestId,标识哪个用户发起的请求;Device回应时,也需要原封不动的回应此Option值。
云端发给Device的请求在COAP_OPT_DEV_ID扩展Option中附带devId,标识发给哪个设备的请求;Device回应时,也需要原封不动的回应此Option值。
设备上不应该理解上述三个Option值的格式及内容,只需要原封不动的返回即可。
IF3 APP-Cloud接口请求示例:
POST /userApp/v1/devices/{devId}/services/{sid} HTTP/1.1
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
需增加Authorization报头。
【batch Command】:
关于控制命令的下发有一种特殊的处理情况:由于需要支持batch服务(一个控制命令中需要下发多个服务参数),POST命令的body结构体需要做相应的修改。即当下发的是batch服务,那么其对应的POST命令的body的格式规范如下:
POST /batchCmd
{
"type":4,
"actions": [
{
"sid": "sid1",
"data": {
"characteristicName1": "value1"
}
},
{
"sid": "sid2",
"data": {
"characteristicName1": "value1"
}
}
]
}
对于设备控制命令的POST请求头的格式不变(涉及的设备命令接口包括:App->Device,Cloud->Device,APP->Cloud),只需要把“batch”字符串填充到相应的sid里面即可。
11.2 通用数据上报接口
11.2.1 数据上报的场景过程
图1 SSR-DEV-DATA-WAN设备远程上报数据接口
11.2.2 OHOS-DATA-API
【适用范围】IF2
【描述】OpenHarmony设备采集到的数据有变更时,通过此接口上报给云服务器。
【请求】
POST /.sys/data
[
{
"devId": "xxxx",
"services": [
{
"reportId": "123588888", //SDK携带,用于数据上报去重
"sid": "sid1",
"data": {
"characteristicName1": "value1",
"characteristicName2": "value2"
}
}
]
}
]
请求的参数如下:
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
必选 | deviceDataInfo[] | 设备上报的数据 |
【回应】:
成功 { "errcode": 0, "status": 0 }
失败 { "errcode": xxx }
回应的参数如下:
参数 | 必选/可选 | 类型 | 描述 |
---|---|---|---|
errcode | 必选 | Integer | 错误码。 |
status | 可选 | gatewayStatus | 网关当前是否已经登录云的状态。网关和设备之间有此状态值,云和设备/网关之间没有 |
【错误码】:
OHOS_CONNECT_VALIDATE_ERR
11.3 点到点本地控流程
11.3.1 Wi-Fi设备点到点本地控
11.3.1.1 点到点本地控查询操作
【适用范围】点到点本地控
【描述】设备点到点查询操作,向设备发送POST消息,消息中携带的sid来标识需要查询的服务,查询操作会立即返回errcode状态,最终状态通过异步上报方式进行上报。
【请求】POST
【加密】spekekey
IF1.1查询接口请求示例:
POST /e2eCtrl
{
"seq": xxxx, // xxxx为递增数字
"data": [
{
"sid": "sid1"
},
{
"sid": "sid2"
}
]
}
说明:通过服务ID来标识对应具体的服务查询。
IF1.1查询所有服务接口请求示例:
POST /e2eCtrl
{
"seq": xxxx, // xxxx为递增数字
"data": [
{
"sid": "allservices"
}
]
}
说明:通过服务ID固定为allservices。
【回应】:
执行成功,异步方式返回具体查询结果
{
"errcode": 0
}
执行失败,返回错误码。
{
"errcode": xxx
}
11.3.1.2 点到点本地控设置操作
【适用范围】点到点本地控
【描述】对设备上的服务发送实时POST操作都如本文的接口定义。
【请求】POST
【加密】spekekey
IF1.1接口请求示例:
POST /e2eCtrl
{
"seq": xxx, // xxxx为递增数字
"data": [
{
"sid": "sid1",
"data": {
"characteristicName1": "value1"
}
},
{
"sid": "sid2",
"data": {
"characteristicName1": "value1"
}
}
]
}
CoAP点对点操作时,直接通过服务ID对服务进行操作。
【回应】:
执行成功,返回具体查询结果
{
"errcode": 0
}
执行失败,返回错误码。
{
"errcode": xxx
}
11.3.1.3 点到点本地控主动上报
【适用范围】点到点本地控
【描述】对设备上的服务发送实时POST操作都如本文的接口定义。
【请求】POST
【加密】spekekey
请求接口示例
POST /e2eDataChange
{
"seq": xxxx,// xxxx为递增数字
"services": [
{
"sid": "sid1",
"data": {
"characteristicName1": "value1"
}
},
{
"sid": "sid2",
"data": {
"characteristicName1": "value1"
}
}
],
}
执行成功,返回结果
{
"errcode": 0
}
11.3.2 BLE设备点到点本地控
11.3.2.1 查询设备状态(customSecData)
主控设备通过customSecData服务,查询设备状态(携带具体sid)。蓝牙设备收到请求后,返回查询结果或错误码。
说明
vendor中各字段的取值必须与OpenHarmony Profile保持一致。
**加密方式:**spekeKey/sessionKey
请求格式:
{
"seq":xxxx, // xxxx为递增数字
"vendor": [
{
"sid": "sidname"
}
]
}
响应格式:
执行成功,返回具体查询结果。
{
"seq":xxxx, // xxxx为递增数字
"vendor": [
{
"sid": "sidname",
"data": {
"characteristicName1": "value1",
"characteristicName2": "value2"
}
}
]
}
执行失败,返回错误码。
{
"errcode": xxx
}
11.3.2.2 查询设备所有服务(customSecData)
主控设备通过customSecData服务,查询设备所有服务状态(sid为allservices)。蓝牙设备收到请求后,返回是否查询成功。
查询成功后,蓝牙设备还需要主动上报所有服务状态,参见设备主动上报(customSecData)。
说明
vendor中各字段的取值必须与OpenHarmony Profile保持一致。
**加密方式:**spekeKey/sessionKey
请求示例:
{
"seq":xxxx, // xxxx为递增数字
"vendor": [
{
"sid": "allservices"
}
]
}
响应示例:
执行成功,返回0。
{
"errcode": 0
}
设备侧主动上报所查询的所有服务状态。
{
"seq":xxxx, // xxxx为递增数字
"vendor": [
{
"sid": "sidname1",
"data": {
"characteristicName1": "value1",
"characteristicName2": "value2"
}
},
{
"sid": "sidname2",
"data": {
"characteristicName1": "value1",
"characteristicName2": "value2"
}
}
]
}
执行失败,返回错误码。
{
"errcode": xxx
}
11.3.2.3 查询设备信息(customSecData)
主控设备通过customSecData服务,查询设备信息。蓝牙设备收到请求后,返回是否查询成功。
查询成功后,蓝牙设备还需要主动上报设备版本号信息,参见设备主动上报(customSecData)。
说明
vendor中各字段的取值必须与OpenHarmony Profile保持一致。
加密方式: spekeKey/sessionKey
请求示例:
{ "seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"deviceinfo",
"source":"gw"** // 如果source字段取值为"gw",表明主控设备为网关;如果不携带该字段,表示主控设备为手机。
}]
}
响应示例:
执行成功,返回0。
{"errcode": 0}**
设备侧主动上报所查询的设备信息。
{
"seq":xxxx,// xxxx为递增数字
"vendor":[{
"sid":"deviceinfo",
"data":[{
"hiv":"1.0", // 可选,HarmonyConnect版本号
"fwv":"1.0", // 必选,固件版本号
"hwv":"1.0", // 必选,硬件版本号
"swv":"1.0", // 可选,软件版本号
}]
}]
}
执行失败,返回错误码。
{"errcode": xxx}
11.3.2.4 控制设备状态(customSecData)
主控设备通过customSecData服务,发送设备状态控制指令。蓝牙设备收到请求后,返回是否执行成功。
操作执行成功后,蓝牙设备还需要主动上报最新的状态,参见设备主动上报(customSecData)。
加密方式: spekeKey/sessionKey
请求示例:
{
"seq":xxxx**,// xxxx为递增数字**
"vendor":[{
"sid":"onoff",
"data":{"onoff":0**}**
},{
"sid":"brushstregth",
"data":{"brushstregth":1**}**
}]
}
响应示例:
执行成功,返回0。
{"errcode": 0}
执行失败,返回错误码。
{"errcode": xxx}
11.4 局域网本地控流程
【适用范围】局域网本地控
【描述】对设备上的服务发送实时GET操作都如本文的接口定义。
【请求】GET
【加密】authcode
IF5接口请求示例:
GET /{sid}
CoAP点对点操作时,直接通过服务ID对服务进行操作。
【回应】:
执行成功,返回具体查询结果
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
执行失败,返回错误码。
{
"errcode": xxx
}
【适用范围】点到点本地控
【描述】对设备上的服务发送实时POST操作都如本文的接口定义。
【请求】POST
【加密】authcode
IF5接口请求示例:
POST /{sid}
{
"characteristicName1": "value1",
"characteristicName2": "value2"
}
CoAP点对点操作时,直接通过服务ID对服务进行操作。
【回应】:
执行成功,返回具体查询结果
{
"errcode": 0
}
执行失败,返回错误码。
{
"errcode": xxx
}
11.5 设备解除绑定流程(TODO)
11.6 云端删除设备的过程
如下图所示,用户从云端删除设备时,如果设备在线,云端调用删除设备接口删除;如果是离线设备,设备重试登录时,通过返回OHOS_CONNECT_DEV_DELETED错误码告知设备已被删除。已被删除的设备需要自行删除本地的devId和secret、psk以及WiFi参数,并且停止连接云服务器。
图2 SSR-DEV-DEL-ONLINE 用户删除在线的直连云设备过程
图3 SSR-DEV-DEL-OFFLINE 用户删除离线的直连云设备过程
当删除离线设备时,在下次设备上电登录时,也是通过OHOS_CONNECT_DEV_DELETED错误码告知设备已被删除。
11.7 设备恢复出厂流程
智能组网终端有多个途径恢复出厂,恢复出厂后,无法告知平台;智能组网终端清除当前的devId/secret以及PSK等信息,标记下当前处于待激活状态。 下一次设备上电后,一旦获取到IP,并且可以访问平台时,先向平台发起注册(/.sys/register),注册成功后断开与设备的连接,重新再接受新的用户激活。 注:当APP用户发起注册流程的时候,TLS连接将在APP成功激活设备之后重新建立。
11.7.1 直连云设备的恢复出厂过程
如下图所示,直连云的设备恢复出厂后,无法告知云端;设备不能清除当前的devId/secret以及PSK,而是标记下当前处于待注销状态。 下一次设备上电后,一旦获取到IP,并且可以访问云时,需要使用老的登录信息直连到云上,自行注销;然后再接受新的用户激活。
图4 SSR-DEV-RESET 直连云设备的恢复出厂过程
相关文章:

openharmony 软总线-设备发现流程
6.1 设备发现流程 6.1.1 Wi-Fi设备发现 6.1.1.1 Wi-Fi设备发现流程 Wi-Fi设备在出厂状态或者恢复出厂状态下,设备上电默认开启SoftAP模式,SoftAP的工作信道在1,6,11中随机选择,SoftAP的Beacon消息中携带的SSID eleme…...

零信任架构和传统网络安全模式的
零信任到底是一个什么类型的模型?什么类型的思想或思路,它是如何实现的,我们要做零信任,需要考虑哪些问题? 零信任最早是约翰金德瓦格提出的安全模型。早期这个模型也是因为在安全研究上考虑的一个新的信任式模型。他最…...
TCP/IP四层模型:从入门到精通
第一部分:基础概念 1.1 什么是TCP/IP? - TCP/IP 是互联网的基础通信协议簇,定义了数据如何在网络中传输和路由。 - 与OSI七层模型的对比:TCP/IP更简化,分为四层,注重实际应用。 1.2 四层模型结构 1. 应…...

二、QT和驱动模块实现智能家居-----问题汇总1
1、文件地址改变后必须在QT下更改地址 2、指定了QT内Kits下的Sysroot头文件地址,但是还是找不到头文件: 3、提示无法执行QT程序:先干掉之前的QT程序 ps //查看程序PIDkill -9 PID 4、无法执行QT程序 1)未设置环境变量 …...

10、HTTP/3有了解过吗?【中高频】
HTTP/2 虽然具有多个流并发传输的能力,但是传输层是 TCP 协议,依然存在缺陷: 队头阻塞,HTTP/2 是基于 TCP 协议来传输数据的,TCP 是字节流协议,TCP 层必须保证收到的字节数据是完整、连续的,当「…...

基于https虚拟主机配置
一、https介绍 http 明文,80/tcp https 密文,443/tcp 二、安全性保障 1、数据安全性 数据加密 2、数据完整性 3、验证身份的真实性、有效性 三、数据安全性 手段:加密 发送方加密数据,接收方解密数据 对称加密算法 加密、解密数据…...

小白入坑向:Java 全栈系统性学习推荐路线之一
文章目录 一、 引言1.1 学习路径:1.2 技术栈全景概述1.3 前沿技术与趋势预判 二、 前端篇2.1 基础知识2.2 进阶技术2.3 前端框架与工具 三、 后端篇3.1 Java 基础3.2 进阶与新特性 四、 企业级框架与开发工具4.1 构建与项目管理4.2 核心框架4.3 数据持久层4.4 微服务…...

云原生存储架构:构建数据永续的新一代存储基础设施
引言:重新定义数据基础设施边界 蚂蚁集团基于Ceph构建的全闪存存储集群达到EB级规模,单集群IOPS突破1亿,延迟稳定在200μs内。Snowflake的存储计算分离架构使其数据湖查询速度提升14倍,存储成本降低82%。Gartner预测到2025年70%企…...

QTableWidget之表格列的隐藏与显示(折叠)
今天晚上花点时间研究一下表格列的显隐问题(类似与excel的隐藏列功能),在网络上搜罗了一通资料,没现成的例子作为借鉴,只能自己研究编写了。现在将过程记录下来,以便日后翻阅。 首先声明:因为时…...
Leetcode3146. 两个字符串的排列差
题目描述: 给你两个字符串 s 和 t,每个字符串中的字符都不重复,且 t 是 s 的一个排列。 排列差 定义为 s 和 t 中每个字符在两个字符串中位置的绝对差值之和。 返回 s 和 t 之间的 排列差 。 代码思路: 建立字符位置映射&…...

二百八十五、华为云PostgreSQL——建分区表并设置主键
一、目的 在PostgreSQL里建表,设置主键,三个字段确认数据的唯一性。设置分区字段,按月分区 二、PostgreSQL版本 三、PostgreSQL 9.2.4 版本缺点 在 PostgreSQL 9.2.4 中,虽然你可以创建分区表,但需要注意的是&#…...

系统架构设计师-第3章 数据库设计
【本章学习建议】 根据考试大纲,本章主要考查系统架构设计师单选题,预计考5分左右,以及案例分析1题,25分。对应第二版教材2.3.3小节以及第6章,主要考点在第6章,这里一起合并到本章课程中。 3.1 数据库基本…...

SAP MDG —— MDG on S/4HANA 2023 FPS03 创新汇总
文章目录 MDG 基于SAP S/4HANA 2023 FPS03的创新BP/C/S:消息控制BP/C/S:手工分配数据控制者MDG-F:使用S/4扩展数据校验功能生成式AI可用于协助自定义对象的数据变更/同时可总结批量变更的内容 MDG 基于SAP S/4HANA 2023 FPS03的创新 由于从S…...

软考中级-数据库-3.2 数据结构-数组和矩阵
数组 一维数组是长度固定的线性表,数组中的每个数据元素类型相同。n维数组是定长线性表在维数上的扩张,即线性表中的元素又是一个线性表。 例如一维数组a[5][a1,a2,a3,a4,a5] 二维数组a[2][3]是一个2行2列的数组 第一行[a11,a12,a13] 第二行[a21,a22,a23…...
有符号数和无符号数的加减运算
一、无符号数的加减运算 加法 规则:直接按二进制逐位相加,若最高位产生进位(即结果超出(2^n)范围),则结果对(2^n)取模((n)为位数)。示例(8位无符号数): (200 …...

动态链接器(十):重定位
ELF文件中有许多种类型的重定位条目,这些重定位条目指导动态链接器在加载或运行时解析符号地址,确保程序能够正确地引用动态库中的函数和变量。 本文主要介绍那些与动态链接有关的重定位条目(主要介绍Rela相关的,Rel相关的不作介…...

EGO-Planner的无人机视觉选择(yolov5和yolov8)
EGO-Planner的无人机视觉选择(yolov5和yolov8) 效果 yolov5检测效果 yolov8检测效果 一、YOLOv8 vs YOLOv5:关键差异解析 1. 训练效率:为何YOLOv8更快? 架构轻量化 YOLOv8采用C2f模块(Cross Stage Partia…...

IO标准函数和时间函数
1、将当前的时间写入到time. txt的文件中,如果ctrlc退出之后,在再次执行支持断点续写 1.2022-04-26 19:10:20 2.2022-04-26 19:10:21 3.2022-04-26 19:10:22 //按下ctrlc停止,再次执行程序 4.2022-04-26 20:00:00 5.2022-04-26 20:00:0…...

为AI聊天工具添加一个知识系统 之133 详细设计之74通用编程语言 之4 架构及其核心
本篇继续讨论 通用编程语言。 说明:本阶段的所有讨论都是围绕这一主题展开的,但前面的讨论分成了三个大部分(后面列出了这一段的讨论题目的归属关系)-区别distinguish(各别): 文化和习俗。知识…...
【零基础到精通Java合集】第二十三集:G1收集器深度解析
课程标题:G1收集器深度解析——面向大内存与低延迟的现代垃圾回收器(15分钟) 目标:掌握G1核心设计思想、运行机制与调优策略,理解其如何平衡吞吐量与低延迟 0-1分钟:课程引入与G1设计目标 以“城市交通智能调度”类比G1核心思想:将堆内存划分为多个区域(Region),动…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...

el-switch文字内置
el-switch文字内置 效果 vue <div style"color:#ffffff;font-size:14px;float:left;margin-bottom:5px;margin-right:5px;">自动加载</div> <el-switch v-model"value" active-color"#3E99FB" inactive-color"#DCDFE6"…...
VTK如何让部分单位不可见
最近遇到一个需求,需要让一个vtkDataSet中的部分单元不可见,查阅了一些资料大概有以下几种方式 1.通过颜色映射表来进行,是最正规的做法 vtkNew<vtkLookupTable> lut; //值为0不显示,主要是最后一个参数,透明度…...

微服务商城-商品微服务
数据表 CREATE TABLE product (id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 商品id,cateid smallint(6) UNSIGNED NOT NULL DEFAULT 0 COMMENT 类别Id,name varchar(100) NOT NULL DEFAULT COMMENT 商品名称,subtitle varchar(200) NOT NULL DEFAULT COMMENT 商…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...

【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...

学校时钟系统,标准考场时钟系统,AI亮相2025高考,赛思时钟系统为教育公平筑起“精准防线”
2025年#高考 将在近日拉开帷幕,#AI 监考一度冲上热搜。当AI深度融入高考,#时间同步 不再是辅助功能,而是决定AI监考系统成败的“生命线”。 AI亮相2025高考,40种异常行为0.5秒精准识别 2025年高考即将拉开帷幕,江西、…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...
基于Java Swing的电子通讯录设计与实现:附系统托盘功能代码详解
JAVASQL电子通讯录带系统托盘 一、系统概述 本电子通讯录系统采用Java Swing开发桌面应用,结合SQLite数据库实现联系人管理功能,并集成系统托盘功能提升用户体验。系统支持联系人的增删改查、分组管理、搜索过滤等功能,同时可以最小化到系统…...