一、设备接入分两个步骤,设备认证和设备交互

  1. 设备认证

    • 加密认证(推荐)
    • 简单认证
    • EMQX支持的其他认证方式
  2. 设备交互

    • 发布物模型、设备信息、时钟同步相关Mqtt主题
    • 订阅物模型、设备升级、时钟同步相关Mqtt主题
  3. 参考sdk,基于Arduino,使用ESP8266芯片开发 >>


二、设备认证

1. 加密认证

系统推荐使用的认证方式,支持设备禁用、自动添加设备功能。产品详情中获取产品编号、Mqtt账号、Mqtt密码和产品秘钥,密码通过产品秘钥进行AES加密,传递到后端。后端通过产品秘钥解密进行认证。连接Mqtt消息服务器需要提供唯一的客户端ID、用户名和密码,具体格式如下:

# 客户端ID
clientId = deviceNumber & productId 

# 用户名
userName = wumei-smart

# 密码
password = mqtt密码 & userId & 过期时间

  • 客户端ID等于设备编号 + 产品编号,用 & 符号连接,中间无空格;
  • 用户名直接输入Mqtt账号
  • 密码等于Mqtt密码 + 用户ID + 密码过期时间,然后进行AES加密。用户ID就是登陆用户的ID,Admin账号是1。为了安全,密码过期时间应该在24小时以内,采用时间戳格式,精确到毫秒。

账号配置信息示例:

clientId = "D6329VL54419L1Y0&2"
userName = "wumei-smart"
password = "/W2A/4MK+9cEGBhyBDgr2K5c62DAjAK4m0b5pvwxX6FFMzI3h1pUmaDY3BH1P2mI"

2. 简单认证

简单认证使用后端yaml文件配置的账号信息,安全性低,暂不支持设备禁用、自动添加设备功能,客户端ID为设备编号,推荐测试环境使用。文件位于:
wumei-smart/springboot/wumei-admin/src/main/resources/application.yml

  # mqtt 配置  
  mqtt:
    username: wumei-smart                    # 账号
    password: wumei-smart                    # 密码
    host-url: tcp://localhost:1883           # mqtt连接tcp地址

账号配置信息示例:

# 客户端Id等于设备编号,没有产品ID
clientId = "D6329VL54419L1Y0"
userName = "wumei-smart"
password = "wumei-smart"

3. EMQX支持的其他认证方式

系统同时支持直接使用EMQX的其他认证方式,但是不支持设备禁用,客户端ID等于设备编号。具体参考官网


4. 设备获取当前时间

获取当前时间,可以调用系统的NTP时间接口,接口请求时发送设备当前运行毫秒数,返回设备发送时间、服务端接收时间、服务端发送时间。然后获取设备当前运行毫秒数,作为设备接收间。最后用公式计算出设备当前的时间,时间必须以毫米为单位。在线时间戳工具

# deviceSendTime值为设备当前运行的毫秒数
http://localhost:8080/iot/tool/ntp?deviceSendTime=35768

# 计算时间
设备当前时间 = (服务端接收时间 + 服务端发送时间 + 设备接收时间 - 设备发送时间) / 2

5. AES加密说明

采用AES的CBC加密模式,偏移量固定为 wumei-smart-open 16位,输出为Base64。加解密工具>>

加密模式:  CBC
填    充:  pkcs5padding
数 据 块:  128位
偏 移 量:  wumei-smart-open
输    出:  base64

密    码:  对应系统的产品秘钥
加密内容:  mqtt密码 & userId & expireTime



三、设备交互

{productId} 代表产品ID, {deviceNum} 代表设备编号。通过web端获取产品ID和设备编号,如果使用自动添加设备,设备编号可以自定义或者使用设备MAC地址,设备认证成功后会在后端自动添加一个对应的设备实体。

  1. 订阅主题
主题 描述
/{productId}/{deviceNum}/ota/get 订阅设备升级
/{productId}/{deviceNum}/property/get 订阅属性
/{productId}/{deviceNum}/property-online/get 订阅属性(在线模式)
/{productId}/{deviceNum}/function/get 订阅功能
/{productId}/{deviceNum}/function-online/get 订阅功能(在线模式)
/{productId}/{deviceNum}/monitor/get 订阅实时监测信号(根据监测次数和间隔,然后发布监测数据)
/{productId}/{deviceNum}/ntp/get 订阅时钟同步(可选,用于同步设备的当前时间)
  1. 发布主题
主题 描述
/{productId}/{deviceNum}/info/post 发布设备信息
/{productId}/{deviceNum}/property/post 发布属性(包括监测数据,可定时上报监测数据)
/{productId}/{deviceNum}/function/post 发布功能
/{productId}/{deviceNum}/event/post 发布事件
/{productId}/{deviceNum}/monitor/post 发布实时监测数据,只用于显示,不会存储
/{productId}/{deviceNum}/ntp/post 发布时钟同步(可选)

  1. 数据格式(设备和系统交互使用JSON格式)

    • 发布设备信息,对应主题:/info/post
    # 描述:设备上电后发布设备信息
    # rssi             设备强度(信号极好[-55— 0],信号好[-70— -55],信号一般[-85— -70],信号差[-100— -85])
    # status           设备状态,固定为3,表示在线
    # userId           用户的ID
    # firmwareVersion  固件版本
    
    {
         "rssi": -20,
         "firmwareVersion": 1.10,
         "status": 3,
         "userId": 1
    }
    

    • 订阅OTA升级,对应主题:/ota/get
    # 描述:订阅到设备升级消息后,根据版本号,Http请求下载固件并升级
    
    {
        "version": 1.1
    }
    

    • 订阅实时监测,对应主题:/monitor/get
    # 描述:订阅到实时监测消息,根据数量和间隔发布实时监测数据
    # count      数量
    # interval   间隔,毫秒为单位
    
    {
        "count": 60,
        "interval": 1000
    }
    

    • 发布实时监测,对应主题:/monitor/post
    # 描述:根据订阅到的实时监测消息,发布指定数量和间隔的监测数据
    # id       标识符,实时监测是物模型中的属性,产品详情中查看标识符,对应id值
    # value    设备采集的值,只能是整数或者小数
    # remark   备注可选,可为空或者使用设备当前时间
    
    [{
        "id": "temperature",
        "value": "27.43",
        "remark": ""
    }, {
        "id": "humidity",
        "value": "32.18",
        "remark": ""
    }]
    

    • 发布时钟同步,对应主题:/ntp/post
    # 描述:可选,发布时钟同步消息,服务端订阅到后下发时钟同步消息
    # deviceSendTime 设备发送时间
    
    {
        "deviceSendTime": "1592361428000"
    }
    

    • 订阅时钟同步,对应主题:/ntp/get
    # 描述:可选,订阅到时钟同步消息,计算当前时间 = (服务端接收时间 + 服务端发送时间 + 设备接收时间 - 设备发送时间) / 2
    # deviceSendTime  设备发送时间
    # serverRecvTime  服务端接收时间
    # serverSendTime  服务端发送时间
    
    {
        "deviceSendTime": "1592361428000",
        "serverSendTime": "1592366463548",
        "serverRecvTime": "1592366463548"
    }
    

    • 发布属性/功能/事件,对应主题:/property/post/function/post/event/post
    # 描述:属性、功能、事件都属于物模型,Json定义是一样的。`value` 的值如果是布尔类型,值为"0"或者"1",代表打开/关闭;枚举类型对应枚举项的键值(例如 "1",代表中速档位);数组类型是以英文逗号分隔的字符串。
    # id      标识符,产品详情中查看物模型,对应物模型的标识符
    # value   对应值,查看物模型中定义
    # remark  可选,备注信息,可在设备日志信息中查看到
    
    [{
        "id": "gear",
        "value": "1",
        "remark": "备注信息"
    } {
        "id": "switch",
        "value": "0",
        "remark": "备注信息"
    }]
    

    • 订阅属性/功能,对应主题:/property/get/function/getproperty-online/get/function-online/get
    # 描述:属性、功能、事件都属于物模型,Json定义是一样的,订阅的消息没有 `remark` 备注信息。属性和功能的在线模式和普通模式,用于区分不同种类消息,但是设备的处理都是一样的。例如都订阅到消息打开开关,设备的处理都是把开关打开。   
    # id     标识符,产品详情中查看物模型,对应物模型的标识符
    # value  对应值,查看物模型中定义,同上
    
    [{
        "id": "gear",
        "value": "1"
    } {
        "id": "switch",
        "value": "0"
    }]