Skip to content

移动模块接入方案

词汇表

名词 含义
移动模块 2G、3G、4G模块
ctrlKey 控制设备时使用的key, 云端颁发,32个字节
bindKey 绑定/解绑设备时使用的key, 云端颁发,32个字节
prodKey 产品唯一标识(即产品密钥), 开发者在控制台上添加产品时自动生成,32个字节
devTid 设备唯一ID,该值由云端分配
devPriKey Device Private Key,即设备私钥,该值由云端分配,并和devTid一一对应
serviceHost 云端服务地址
servicePort 云端服务端口

文档背景

需要制定移动模块的接入流程,并最终形成一个方案。

前置信息

以下所有章节里,数据均为16进制值。假如文档描述的数据格式(内存数据)为:

48 05 04 01 52

则实际发送和接收的数据均是序列化后的16进制字符串:

4805040152

c 语言对应的输出结果为:printf("%2x",0x4805040152)

也就是说:设备和云端传输数据时,需要进行二进制数据到16进制字符串的序列号和反序列化操作,实际在网络上传输的是字符串数据。

后面章节不再赘述。

基本帧格式

上图是帧的基本格式,具体由以下几个部分组成:

帧头

帧头的长度为1个字节,是帧的起始标识,指定为H或十六进制0x48

帧长

帧长的长度为1个字节,是整个帧内容(包括帧头、帧长、校验码等)的字节个数,取值:[0x06, 0xFE]

帧类型

帧类型的长度为1个字节,用于识别该帧的类型,取值见“帧类型列表”。

帧序号

帧序号的长度为1个字节,取值[0x00, 0xFF],循环累加,用来标识帧的顺序,该字段主要用于一条消息需要分包发送的情况,默认可填充0x00,表示不分包;

msgid

msgid的长度为2个字节,取值[0x0000, 0xFFFF],表示该条消息的编号ID,回应消息的msgid在一些业务场景下必须要和请求消息的msgid保持一致,请注意和“帧序号”的区别;默认可填充0x0000, 表示该帧消息不关心该字段

  • 在APP端,建议msgid从app框架提供的以下接口获取 Hekr.msgId(function(msgid) { //do something })
  • 在设备端,根据需要自动生成或者使用请求中的msgid

有效数据

有效数据的长度不确定,跟具体业务有关,上图中使用n来代表实际长度。

当然,厂家也可以在厂家控制台->产品管理->添加新产品->管理->参数信息->产品参数信息页面里设计自己产品的有效数据格式。

校验码

校验码的长度为1个字节,是整个帧内容(包括帧头、帧长等)的数据和,超过0XFF取低8位(即1个字节)。

通信协议

通信协议构建在基本帧格式之上,具体体现在如下的各个指令及其应答。

统一应答格式

一般指令的应答格式如下,个别指令的应答不一样,会单独列出。

48 {帧长 1byte} {帧类型 1byte} {帧序号 1byte} {msgid 2byte} {成功/错误码 4bytes} {校验码 1byte}

注意,统一应答格式里:

  • 帧类型和指令里的帧类型对应,对应表请参考帧类型取值表
  • 帧序号必须和指令里的帧序号一致
  • 成功/错误码请参考最下面的错误码表

帧类型取值表

码值 含义
0x00 通用错误返回
0x01 设备请求校验设备ID
0x02 0x01的应答帧
0x03 设备请求身份认证
0x04 0x03的应答帧
0x05 设备上报详情
0x06 0x05的应答帧
0x07 APP发送数据到设备
0x08 0x07的应答帧
0x09 设备发送数据到APP
0x0A 0x09的应答帧
0x0B 设备发送心跳
0x0C 0x0B的应答帧
0x0D 设备从云端同步时间
0x0E x0D的应答帧

设备和云端建立通道

设备和云端建立通道,需要两个步骤:

  1. 设备请求云端校验设备ID。因为设备ID是由云端统一颁发的,所以具备唯一性,因此设备连接云端首先要校验其ID是否合法。
  2. 设备身份认证。设备需要使用其生产过程中写入的devPriKey来加密某些随机值,并发送到云端验证其是否具备连接云端的钥匙。

通用错误返回

返回格式

48 09 00 {帧序号 1byte} {error code 4bytes} {校验码 1byte}

设备请求校验设备ID

指令格式

48 45 01 {帧序号 1byte} {prodKey 32bytes} {devTid 32bytes} {校验码 1byte}

其中01是该指令的帧类型。

应答格式

成功返回如下特殊格式,失败则返回统一应答。

48 25 02 {帧序号 1byte} {hexRandomKey 16bytes} {校验码 1byte}

其中02是应答的帧类型。

调用说明

hexRandomKey 是云端返回的一个随机字符串(16字节), randomKey=printf("%2x",hexRandomKey)。

设备身份认证

指令格式

48 15 03 {帧序号 1byte} {authKey 16bytes} {校验码 1byte}

其中03是该指令的帧类型。

应答格式

统一应答,且应答的帧类型是04

调用说明

authKey计算方法:

authKey = MD5(randomKey + devTid + devPriKey)  // '+'号代表内存中数据直接拼接

devTid和devPriKey的含义请参考词汇表。云端校验authKey成功后,设备身份认证最终通过。

已下面例子说明authKey的计算(D表示设备,C表示云端, 为增强可读性补充空格,实际发送时无空格):

proKey:fa43e10a44bc8e624d9f008a3feaaa01

设备devTid:9e982ed5dd2c4c7ca744bc76ef4af044

privateKey:4a83550599a94f1db9345d8645f79234

D => C: 484501 00 6661343365313061343462633865363234643966303038613366656161613031 3965393832656435646432633463376361373434626337366566346166303434 24
C => D: 481502 00 4871745161336379676b71664c623554 2d
D => C: 481503 01 60f153ece1c40698910fb12b2035f96e 6c
C => D: 480904 01 0000000056

6661343365313061343462633865363234643966303038613366656161613031 则是通过将fa43e10a44bc8e624d9f008a3feaaa01 字符串转16进制后得到的。

3965393832656435646432633463376361373434626337366566346166303434 则是通过将 9e982ed5dd2c4c7ca744bc76ef4af044 字符串转16进制后得到的。

得到16进制的结果 result=484501 00 6661343365313061343462633865363234643966303038613366656161613031 3965393832656435646432633463376361373434626337366566346166303434 24(注意去除空格,空格只是为了看着容易区分帧)通过c程序的printf("%2x",result)得到的字符串,然后将这个字符串发往云端服务器。

randomKey 为 4871745161336379676B71664C623554,即c程序通过printf("%2x",hexRandomKey), 注意云端向设备发送authKey时是按字符串写入,即通过 printf("%2x",authKey)得到的字符串

let authKey = md5('4871745161336379676B71664C623554' + '9e982ed5dd2c4c7ca744bc76ef4af044' + '4a83550599a94f1db9345d8645f79234')
assertEqual( hex(authKey), '60f153ece1c40698910fb12b2035f96e' )

设备上报详情

指令格式

48 5e 05 {帧序号 1byte} {模块网络制式编号 1byte} {基站信息1 4bytes} {基站信息2 4bytes} {基站信息3 4bytes} {基站信息4 bytes} {基站信息5 4bytes} {基站信息6 4bytes} {经度整数部分 2bytes} {经度小数部分 4bytes} {纬度整数部分 2bytes} {纬度小数部分 4bytes} {预留 52bytes} {校验和 1byte}

其中05是该指令的帧类型。

应答格式

统一应答,且应答的帧类型是06

调用说明

模块网络制式编号表

模块网络制式 编号 基站信息说明(按1~6顺序) 备注
移动2G 0 {lac} {cellid} {偏离角} {传输距离} {预留} {预留} 参数都是可选
移动3G 1 {lac} {cellid} {偏离角} {传输距离} {预留} {预留} 参数都是可选
移动4G 2 {是否4G基站} {lac} {enodebid} {cellid} {偏离角} {传输距离} 参数都是可选
联通2G 3 {lac} {cellid} {偏离角} {传输距离} {预留} {预留} 参数都是可选
联通3G 4 {lac} {cellid} {偏离角} {传输距离} {预留} {预留} 参数都是可选
联通4G 5 {是否4G基站} {lac} {enodebid} {cellid} {偏离角} {传输距离} 参数都是可选
电信2G 6 {sid} {nid} {bid} {预留} {预留} {预留} 参数都是可选
电信3G 7 {sid} {nid} {bid} {预留} {预留} {预留} 参数都是可选
电信4G 8 {是否4G基站} {lac} {enodebid} {cellid} {偏离角} {传输距离} 参数都是可选

表中专业词汇解释

  • lac — location area code 位置区编码,也叫小区号
  • cellid — 基站编号
  • enodebid — 基站编号,该词汇在4G中专用
  • sid — 系统识别码,每个地级市只有一个sid,是唯一的
  • nid — 网络识别码,由各本地网管理,也就是由地级分公司分配。每个地级市可能有1到3个nid
  • bid — 表示的是网络中的某一个小区,可以理解为基站

更多信息请参考:参考资料1参考资料2

APP发送数据到设备

指令格式

{
    "msgId" : 291,
    "action" : "appSend",
    "params" : {
        "devTid" : "ESP_245EC89",
        "ctrlKey" : 123456789123456789",
        "appTid" : "358974675345",
        "data" : {
            "raw" : "48xx07xx"
        }
    }
}

data.raw的具体格式如下。

48 {帧长 1byte} 07 {帧序号 1byte} {msgid 2byte} {appTid 64bytes} {有效数据 nbytes} {校验码 1byte}

apptid 和 app登录的时候保持一致。

其中07是帧类型。

设备应答格式
48 4B 08 {帧序号 1byte} {msgid 2byte} {appTid 64bytes} {成功/错误码 4bytes} {校验码 1byte}

最佳实践:成功/错误码直接填充 00000000,当有错误的时候发一个devSend(也即是向app发送消息)即可。

app接收数据则是如下格式: 成功。

{
    "msgId" : 291;
    "action" : "appSendResp",
    "code" : 200,
    "desc" : "Success"
    "params": {
        "devTid": "fjkashfj123123",
        "ctrlKey": "fashf123123r5fhhf",
        "appTid": "123123123"
    }
}

失败。

{
    "msgId" : 291,
    "action" : "appSendResp",
    "code" : 错误码,
    "desc" : "错误描述"
}

设备发送数据到APP

指令格式

48 {帧长 1byte} 09 {帧序号 1byte} {msgid 2byte} {有效数据 nbytes} {校验码 1byte}

其中09是帧类型。

应答格式

统一应答,且应答的帧类型是0A

APP 收到的数据格式如下:

{
  "msgId" : 291,
  "action" : "appSendResp",
  "code" : 200,
  "desc" : "success",
  "params" : {
      "devTid" : "ESP_2M_245EC89",
      "ctrlKey" : "123456789123456789",
      "appTid" : "358974675345",
      "data" : {
          "raw" : "48xx0Axx"
      }
  }
}

设备发送心跳

指令格式
48 05 0B {帧序号 1byte} {校验码 1byte}

其中0B是帧类型。

应答格式

统一应答,且应答的帧类型是0C

调用说明

如果30秒内云端没有收到任何数据,则会主动断开与设备的连接,所以设备必要时需要发送心跳指令来保活连接。

设备从云端同步时间

指令格式
48 05 0D {帧序号 1byte} {校验码 1byte}

其中0D是帧类型。

应答格式

48 0D 0E {帧序号1Byte} {毫秒时间戳unint64 8Byte,大端} {校验和 1Byte}

如返回:480d0e01000001689e56e36f13 则 时间戳为00001689e56e36f,也就是 1548844721007

设备生产

设备生产时,需要在其MCU里写入几个值,包括:devTid、devPriKey、bindKey、devPrKey、serviceHost、servicePort。

  • prodKey,厂家可以在氦氪控制台添加新产品完成后,通过以下路径查看。氦氪控制台产品管理相应产品产品信息产品密钥查看。
  • devTid、devPriKey、bindKey:厂家可以在氦氪控制台申请N个唯一ID/设备私钥,并导出csv文件及相应的二维码。路径如下:氦氪控制台产品管理相应产品设备私钥批量生成导出批量生成的二维码及相应的csv文件。
  • serviceHost、servicePort,厂家根据设备使用地写入云端服务地址和端口。中国地区serviceHost写入hub.hekr.me,不同的通讯方式使用不同的端口,明文通道:87(tcp)、88(websocket),加密通道:187(tcp ssl)、188(websocket ssl)。

最终,在设备生产阶段,,厂家需在MCU里写入devTid、prodKey、devPriKey、bindKey、serviceHost、servicePort。方案如下:

  • 在生成的二维码上增加识别号码以便于能清楚区分该二维码所表示的产品、批次、序号。
  • 厂家通过MCU烧写工具写入相应的devTid、devPriKey、bindKey
  • 烧写完成后对应的按序号对设备贴对应的二维码标识图并附带N份备用(根据后续设备需要粘贴的张数)
  • 二维码

移动模块接入流程

下图是移动模块接入的整理流程。

mobile-framework

下面将使用时序图对重要的流程进行说明。

设备和用户绑定

mobile-bind

设备发送数据到APP

mobile-devSend

APP发送数据到设备

错误码表

错误码 提示信息 中文释义 可能造成的原因
1200000 Success 调用成功
1400000 Error 未知错误 该行以下所有1400开头的错误码需要单独处理
1400001 Json parse error json解析错误 json格式错误
1400002 JWT parse error jwt_token解析错误 jwt token错误
1400003 The field {0} contains a value that is too high 属性值过高 发送报文中某属性的值超过了其上限
1400004 The field {0} contains a value that is too low 属性值过低 发送报文中某属性的值低于了其下限
1400005 The value of the field {0} must be an enumerated value 属性值必须为范围内枚举值 发送报文中某属性值不符合其定义的取值范围
1400006 Field not exist 属性不存在 发送报文中存在了未定义的属性
1400008 devTid not match 设备ID不匹配 报文填写的devTid与登录设备的devTid不一致
1400009 App repeat login APP重复登录 同一个appTid的app重复登录
1400010 User does not exist 用户不存在 用户不存在或者uid填错了
1400011 The device does not have this instruction 设备不具有该指令 设备不具备该指令
1400012 Device does not belong to user 设备不属于该用户 设备不再属于该用户
1400013 Device repeat login 设备重复登录 设备同时登录
1400014 Frame parse error 帧解析错误 报文格式或内容错误
1400015 Device last token can not use 设备上一次token已过期无法使用 使用的旧token已经超过上限
1400016 Action not support 该帧行为不被支持 报文中的action填错了
1400017 Device token can not verification 设备token校验错误 设备token错误
1400018 Device not online 设备不在线 设备离线
1400019 App is not logged in app未登录 app未登录或其他原因导致云端认为app已经离线
1400020 Device is not logged in 设备未登录 设备未登录或其他原因导致云端认为设备已经离线
1400022 The device is not found 找不到指定(devTid)设备 当前产品下不存在该设备
1400023 appTid does not match app设备id不匹配 当前发送报文的appTid与绑定设备时的appTid不一致
1400024 You report info does not match your connect server 上报节点信息与实际不符 上报的内容与当时连接节点信息不一致
1400025 RAW not valid, Please check your protocol template 协议不合法,请参照协议模板 48协议串不合法
1400026 AuthKey can't auth authKey 认证失败 填写了错误的authkey
1400027 Product key not available 不是有效的pk 填写了错误的pk
1400028 PinCode or SSID not available pinCode或者ssid无效 填写了无效的pinCode或者ssid
1400029 Bind failed due to timeout error 绑定设备超时错误 绑定设备超时
1400030 Can not bind other manufacture's device 无法绑定其它厂商的设备 APP绑定了非该厂家的设备
1400039 Device license can not verification 设备license不合法 请填写正确的license
1400031 Can not force bind device 无法强绑设备 设备设定为无法强绑,强绑失败
1400032 Invalid Param 参数不合法 协议参数不合法
1400040 frame payload error 帧内容校验失败 可能帧内容或者求和不对
1500000 Internal error 内部错误 服务内部错误
1500001 Link error 链路错误 链路错误

示例代码

C 语言版本

C 语言版本

内存二进制内容序列化为16进制字符串