MQTT物联网协议JSON版

版本:0.0.1

一、概述

二、物模型

什么是物模型

物模型是物联网平台为产品定义的数据模型,用于描述产品的功能。本文介绍物模型相关概念和使用限制。

功能说明

物模型是物理空间中的实体(如传感器、车载装置、楼宇、工厂等)在云端的数字化表示,从属性、服务和事件三个维度,分别描述了该实体是什么、能做什么、可以对外提供哪些信息。定义了物模型的这三个维度,即完成了产品功能的定义。

功能类型 说明
属性(Property) 用于描述设备运行时具体信息和状态。

例如,环境监测设备所读取的当前环境温度、智能灯开关状态、电风扇风力等级等。

属性可分为读写和只读两种类型。读写类型支持读取和设置属性值,只读类型仅支持读取属性值。

服务(Service) 指设备可供外部调用的指令或方法。服务调用中可设置输入和输出参数。输入参数是服务执行时的参数,输出参数是服务执行后的结果。

相比于属性,服务可通过一条指令实现更复杂的业务逻辑,例如执行某项特定的任务。

服务分为异步和同步两种调用方式。

事件(Event) 设备运行时,主动上报给云端的信息,一般包含需要被外部感知和处理的信息、告警和故障。事件中可包含多个输出参数。

例如,某项任务完成后的通知信息;设备发生故障时的温度、时间信息;设备告警时的运行状态等。

事件可以被订阅和推送。

物联网平台支持为产品定义多组功能(属性、服务和事件)。一组功能定义的集合,就是一个物模型模块。多个物模型模块,彼此互不影响。

物模型模块功能,解决了工业场景中复杂的设备建模,便于在同一产品下,开发不同功能的设备。

例如,电暖扇产品的功能属性有电源开关档位(高、中、低)室内温度,您可以在一个模块添加前2个属性,在另一个模块添加三个属性,然后分别在不同设备端,针对不同物模型模块功能进行开发。此时,该产品下不同设备就可以实现不同功能。

物联网平台已提供默认模块,您可根据需要新增自定义模块。每个产品中默认模块和自定义模块总个数不能超过200个。

使用说明

物联网平台通过定义一种物的描述语言来描述物模型模块和功能,称为TSL(Thing Specification Language)。

物模型模块下定义的功能不需要同时包含属性、服务和事件,按需配置即可。

物模型TSL文件格式为JSON。您可在物联网平台控制台产品详情页面,单击功能定义页签,单击物模型TSL,查看或导出JSON格式的TSL。相关字段说明,请参见物模型TSL字段说明

物联网平台支持单个和批量添加物模型。批量导入时,您可自定义物模型TSL文件,编写要求,请参见下文。

物模型文件后缀名为.json;文件内容必须符合JSON格式;文件大小不能超过512 KB;文件中有效字符数量不能超过256 KB(256*1024个字符)。

有效字符,指JSON格式内容中,除换行和对齐字符之外的字符。

物模型TSL字段说明

为了完整展示TSL的结构,以下示例中包含所有参数,不代表实际使用中可能出现的组合。参数后的文字为参数说明,非参数值。各参数的使用场景,请参见参数说明。

{
    "schema": "物模型结构定义的访问URL。",
    "profile": {
        "productKey": "当前产品的ProductKey。"
    },
    "properties": [
        {
            "identifier": "属性唯一标识符(物模型模块下唯一)。",
            "name": "属性名称",
            "accessMode": "属性读写类型:只读(r)或读写(rw)。",
            "required": "是否是标准功能的必选属性:是(true),否(false)。",
            "dataType": {
                "type": "属性类型: int(原生)、float(原生)、double(原生)、text(原生)、date(String类型UTC毫秒)、bool(0或1的int类型)、enum(int类型,枚举项定义方法与bool类型定义0和1的值方法相同)、struct(结构体类型,可包含前面7种类型,下面使用"specs":[{}]描述包含的对象)、array(数组类型,支持int、double、float、text、struct)。",
                "specs": {
                    "min": "参数最小值(int、float、double类型特有)。",
                    "max": "参数最大值(int、float、double类型特有)。",
                    "unit": "属性单位(int、float、double类型特有,非必填)。",
                    "unitName": "单位名称(int、float、double类型特有,非必填)。",
                    "size": "数组元素的个数,最大512(array类型特有)。",
                    "step": "步长(text、enum类型无此参数)。",
                    "length": "数据长度,最大10240(text类型特有)。",
                    "0": "0的值(bool类型特有)。",
                    "1": "1的值(bool类型特有)。",
                    "item": {
                        "type": "数组元素的类型(array类型特有)。"
                    }
                }
            }
        }
    ],
    "events": [
        {
            "identifier": "事件唯一标识符(物模型模块下唯一,其中post是默认生成的属性上报事件)。",
            "name": "事件名称。",
            "desc": "事件描述。",
            "type": "事件类型(info、alert、error)。",
            "required": "是否是标准功能的必选事件:是(true),否(false)。",
            "outputData": [
                {
                    "identifier": "参数唯一标识符。",
                    "name": "参数名称。",
                    "dataType": {
                        "type": "属性类型: int(原生)、float(原生)、double(原生)、text(原生)、date(String类型UTC毫秒)、bool(0或1的int类型)、enum(int类型,枚举项定义方法与bool类型定义0和1的值方法相同)、struct(结构体类型,可包含前面7种类型,下面使用"specs":[{}]描述包含的对象)、array(数组类型,支持int、double、float、text、struct)。",
                        "specs": {
                            "min": "参数最小值(int、float、double类型特有)。",
                            "max": "参数最大值(int、float、double类型特有)。",
                            "unit": "属性单位(int、float、double类型特有,非必填)。",
                            "unitName": "单位名称(int、float、double类型特有,非必填)。",
                            "size": "数组元素的个数,最大512(array类型特有)。",
                            "step": "步长(text、enum类型无此参数)。",
                            "length": "数据长度,最大10240(text类型特有)。",
                            "0": "0的值(bool类型特有)。",
                            "1": "1的值(bool类型特有)。",
                            "item": {
                                "type": "数组元素的类型(array类型特有)。"
                            }
                        }
                    }
                }
            ],
            "method": "事件对应的方法名称(根据identifier生成)。"
        }
    ],
    "services": [
        {
            "identifier": "服务唯一标识符(物模型模块下唯一,其中set/get是根据属性的accessMode默认生成的服务)。",
            "name": "服务名称。",
            "desc": "服务描述。",
            "required": "是否是标准功能的必选服务:是(true),否(false)。",
            "callType": "async(异步调用)或sync(同步调用)。",
            "inputData": [
                {
                    "identifier": "入参唯一标识符。",
                    "name": "入参名称。",
                    "dataType": {
                        "type": "属性类型: int(原生)、float(原生)、double(原生)、text(原生)、date(String类型UTC毫秒)、bool(0或1的int类型)、enum(int类型,枚举项定义方法与bool类型定义0和1的值方法相同)、struct(结构体类型,可包含前面7种类型,下面使用"specs":[{}]描述包含的对象)、array(数组类型,支持int、double、float、text、struct)。",
                        "specs": {
                            "min": "参数最小值(int、float、double类型特有)。",
                            "max": "参数最大值(int、float、double类型特有)。",
                            "unit": "属性单位(int、float、double类型特有,非必填)。",
                            "unitName": "单位名称(int、float、double类型特有,非必填)。",
                            "size": "数组元素的个数,最大512(array类型特有)。",
                            "step": "步长(text、enum类型无此参数)。",
                            "length": "数据长度,最大10240(text类型特有)。",
                            "0": "0的值(bool类型特有)。",
                            "1": "1的值(bool类型特有)。",
                            "item": {
                                "type": "数组元素的类型(array类型特有)。"
                            }
                        }
                    }
                }
            ],
            "outputData": [
                {
                    "identifier": "出参唯一标识符。",
                    "name": "出参名称。",
                    "dataType": {
                        "type": "属性类型: int(原生)、float(原生)、double(原生)、text(原生)、date(String类型UTC毫秒)、bool(0或1的int类型)、enum(int类型,枚举项定义方法与bool类型定义0和1的方法相同)、struct(结构体类型,可包含前面7种类型,下面使用"specs":[{}]描述包含的对象)、array(数组类型,支持int、double、float、text、struct)。",
                        "specs": {
                            "min": "参数最小值(int、float、double类型特有)。",
                            "max": "参数最大值(int、float、double类型特有)。",
                            "unit": "属性单位(int、float、double类型特有,非必填)。",
                            "unitName": "单位名称(int、float、double类型特有,非必填)。",
                            "size": "数组元素的个数,最大512(array类型特有)。",
                            "step": "步长(text、enum类型无此参数)。",
                            "length": "数据长度,最大10240(text类型特有)。",
                            "0": "0的值(bool类型特有)。",
                            "1": "1的值(bool类型特有)。",
                            "item": {
                                "type": "数组元素的类型(array类型特有)。"
                            }
                        }
                    }
                }
            ],
            "method": "服务对应的方法名称(根据identifier生成)。"
        }
    ],
    //仅自定义模块的TSL中有以下参数。
    "functionBlockId": "自定义模块的唯一标识符,模块ID。",
    "functionBlockName": "自定义模块名称。",

    //当产品下添加了自定义模块,默认模块TSL中会包含以下参数,表示已添加的自定义模块列表。
    "functionBlocks": [
    {
      "functionBlockId": "自定义模块的唯一标识符,模块ID。",
      "functionBlockName": "自定义模块名称。",
      "productKey": "产品ProductKey。"
    }
  ]
}

三、影子设备

设备影子概览

物联网平台提供设备影子功能,用于缓存设备上报的状态数据和应用程序下发的指令信息。设备在线时,可以直接获取物联网平台指令;设备离线后,再次上线可以主动拉取物联网平台指令。本文主要介绍设备影子的应用场景和使用方法。

什么是设备影子

设备影子是一个JSON文档,用于存储设备上报状态数据和应用程序期望状态信息。JSON数据格式的详细说明,请参见设备影子JSON详解。

每个设备有且只有一个设备影子,设备可以通过MQTT获取和设置设备影子来同步状态,该同步可以是影子同步给设备,也可以是设备同步给影子。

应用场景

在以下场景中,您可选择使用设备影子功能,获取设备上报数据和应用程序期望数据。

应用程序请求获取设备状态。

场景描述:

设备网络不稳定,设备频繁上下线,无法正常响应应用程序的请求。 设备网络稳定,同时响应多个应用程序的请求,即使响应的结果一样,设备本身处理能力有限,也会无法负载多次请求。 使用设备影子机制,设备状态变更,只需同步状态给设备影子一次,应用程序请求获取设备状态,不论应用程序请求数量,和设备是否联网在线,都可从设备影子中获取设备当前状态,实现应用程序与设备解耦。

应用程序获取设备影子中状态的流程图如下,其中数据流转过程,请参见设备主动上报状态。

应用程序下发指令给设备,变更设备状态。

场景描述:设备处于下线状态,或设备网络不稳定,设备频繁上下线,应用程序发送控制指令给设备,设备不在线,指令就会发送失败。

使用设备影子机制,可以将应用程序下发的指令,携带时间戳存储到设备影子中。设备再上线时,获取设备影子中指令,并根据时间戳确定是否执行。

应用程序更新设备状态的流程图如下,其中数据流转过程,请参见应用程序改变设备状态、设备主动获取影子内容、设备主动删除影子属性。

设备影子JSON详解

设备影子JSON文档示例:

{
    "state": {
        "desired": {
            "color": "RED", 
            "sequence": [
                "RED", 
                "GREEN", 
                "BLUE"
            ]
        }, 
        "reported": {
            "color": "GREEN"
        }
    }, 
    "metadata": {
        "desired": {
            "color": {
                "timestamp": 1469564492
            }, 
            "sequence": {
                "timestamp": 1469564492
            }
        }, 
        "reported": {
            "color": {
                "timestamp": 1469564492
            }
        }
    }, 
    "timestamp": 1469564492, 
    "version": 1
}

JSON属性描述,如下表所示。

属性 描述
desired 设备的预期状态。仅当设备影子文档具有预期状态时,才包含desired部分。
应用程序向desired部分写入数据,更新事物的状态,而无需直接连接到该设备。
reported 设备的报告状态。设备可以在reported部分写入数据,报告其最新状态。
应用程序可以通过读取该参数值,获取设备的状态。
JSON文档中也可以不包含reported部分,没有reported部分的文档同样为有效影子JSON文档。
metadata 当用户更新设备状态文档后,设备影子服务会自动更新metadata的值。
设备状态的元数据的信息包含以 Epoch 时间表示的每个属性的时间戳,用来获取准确的更新时间。
timestamp 影子文档的最新更新时间。
version 用户主动更新版本号时,设备影子会检查请求中的version值是否大于当前版本号。如果大于当前版本号,则更新设备影子,并将version值更新到请求的版本中,反之则会拒绝更新设备影子。
该参数更新后,版本号会递增,用于确保正在更新的文档为最新版本。
version参数为long型。为防止参数溢出,您可以手动传入-1将版本号重置为0。

设备影子支持数组。更新数组时必须全量更新,不能只更新数组的某一部分。

更新数组数据示例: 初始状态:

{
    "reported" : { 
        "colors" : [
            "RED", 
            "GREEN",
            "BLUE" 
        ]
    }
}

更新:

{
    "reported" : {
        "colors" : [
            "RED"
        ] 
    }
}

最终状态:

{
    "reported" : {
        "colors" : [
            "RED"
        ] 
    }
}

设备影子数据流

设备影子数据通过Topic进行流转,主要包括设备上报状态到设备影子、应用程序更改设备状态、设备离线再上线后主动获取设备影子信息,和设备端请求删除设备影子中的属性信息。本文介绍设备影子Topic及其数据格式。

设备影子Topic

物联网平台已为每个设备预定义了两个Topic,用于实现设备影子数据流转。

/shadow/update/${YourProductKey}/${YourDeviceName}

设备和应用程序发布消息到此Topic。物联网平台收到该Topic的消息后,将消息中的状态更新到设备影子中。

/shadow/get/${YourProductKey}/${YourDeviceName}

设备影子更新状态到该Topic,设备订阅此Topic获取最新消息。

使用示例

本文以灯泡设备为例,说明设备、设备影子以及应用程序之间的通信,主要介绍设备主动上报状态、应用程序改变设备状态、设备主动获取影子内容,和设备主动删除影子属性。

示例中,产品的ProductKey是a1PbRCF****;设备名称DeviceName是lightbulb。设备以QoS=1发布消息和订阅两个设备影子Topic。

设备主动上报状态

设备在线时,主动上报设备状态到影子,应用程序主动获取设备影子状态。

数据流转过程如下图所示。

  1. 当灯泡lightbulb上线时,使用Topic /shadow/update/a1PbRCF****/lightbulb上报最新状态到影子。 发送的JSON消息格式:
{
    "method": "update", 
    "state": {
        "reported": {
            "color": "red"
        }
    }, 
    "version": 1
}

上报参数说明 参数 说明 method 表示设备或者应用程序请求设备影子时的操作类型。 当执行更新操作时,method为必填字段,设置为update。

state 表示设备发送给设备影子的状态信息。 reported为必填字段,状态信息会同步更新到设备影子的reported部分。

version 表示设备影子检查请求中的版本信息。 只有当新版本大于当前版本时,设备影子才会接收设备端的请求,并更新设备影子版本。

如果version设置为-1时,表示清空设备影子数据,设备影子会接收设备端的请求,并将设备影子版本更新为0。

2.设备影子接收到灯泡上报的状态数据后,更新影子文档。

{
    "state": {
        "reported": {
            "color": "red"
        }
    }, 
    "metadata": {
        "reported": {
            "color": {
                "timestamp": 1469564492
            }
        }
    }, 
    "timestamp": 1469564492, 
    "version": 1
}
  1. 影子文件更新后,设备影子会返回结果给设备(灯泡),即发送消息到设备订阅的Topic /shadow/get/a1PbRCF****/lightbulb中。
{
    "method": "reply", 
    "payload": {
        "status": "success", 
        "version": 1
    }, 
    "timestamp": 1469564576
}
  {
    "method": "reply", 
    "payload": {
        "status": "error", 
        "content": {
            "errorcode": "${errorcode}", 
            "errormessage": "${errormessage}"
        }
    }, 
    "timestamp": 1469564576
}

表 2. 错误码说明

errorCode errorMessage
400 不正确的JSON格式。
401 影子数据缺少method信息。
402 影子数据缺少state字段。
403 影子数据中version值不是数字。
404 影子数据缺少reported字段。
405 影子数据中 reported属性字段为空。
406 影子数据中 method是无效的方法。
407 影子内容为空。
408 影子数据中reported属性个数超过128个。
409 影子版本冲突。
500 服务端处理异常。

四、使用消息通信Topic

五、消息解析

参考文档