产品功规范描述
1. 快速入门
1.1 设备
在现实中,常见的物理设备基本都包含了诸多功能,如:
Example 1.1
| 设备 | 智米风扇 | 智米霾表 | 飞利浦灯泡 | 智米空气净化器 |
|---|---|---|---|---|
| 功能1 | 可开关 | 可以查询空气质量 | 可开关 | 可开关 |
| 功能2 | 可调节风速 | 可充电 | 可调节亮度 | 可调节风速 |
| 功能3 | 可充电 | 可查询电量 | 可调节颜色 | 可查询滤芯生命值 |
| 功能4 | 可查询电量 | 可查询充电状态 | 可调节色温 | 可查询空气质量 |
| 功能5 | 可查询充电状态 |
1.2 功能分组
不同的设备的某些功能可能是一样的,比如:
-
智米风扇和智米霾表都有电池,都可以:
-
充电
-
查询电量
-
查询充电状态
-
-
智米霾表和智米空气净化器都可以:
- 查询空气质量
-
智米风扇和智米空气净化都可以:
- 调节风速
为了方便,有必要对功能进行分组,比如:
-
电池
-
空气质量传感器
-
风扇
我们将功能组替换具体功能,那么Example 1.1可以写得更简洁:
Example 1.2
| 设备 | 智米电风扇 | 智米霾表 | 飞利浦灯泡 | 智米空气净化器 |
|---|---|---|---|---|
| 功能组1 | 风扇 | 空气质量传感器 | 灯泡 | 风扇 |
| 功能组2 | 电池 | 电池 | 空气质量传感器 |
1.3 功能组定义
将功能组细化:
Example 1.3
| 功能组 | 风扇 | 电池 | 空气质量传感器 | 灯泡 |
|---|---|---|---|---|
| 功能1 | 可开关 | 可充电 | 可查询PM2.5值 | 可开关 |
| 功能2 | 可调节/查询风速 | 可查询充电状态 | 可调节/查询亮度 | |
| 功能3 | 可查询当前电量 | 可调节/查询色温 | ||
| 功能4 | 可调节/查询颜色 |
1.4 抽象设备描述
通过以上的功能分解,我们可以比较完整地描述一个设备具备的功能了:
-
智米电风扇
-
风扇
-
可开关
-
可调节/查询风速
-
-
电池
-
可充电
-
可查询充电状态
-
可查询当前电量
-
-
用JSON来表达就是这样:
Example 1.4.1
{
"名称": "智米电风扇",
"功能组": [
{
"名称": "风扇",
"功能列表": ["可开关", "可调节/查询风速"]
},
{
"名称": "电池",
"功能列表": ["可充电", "可调节充电状态", "可查询当前电量"]
}
]
}
还有些细节没有确定,比如说:
-
风速的调节到底是按档位来,还是无极变速?
-
电池的电量到底是用百分比表达,还是用毫安?
所以,如果我们把每个细节都确定下来,计算机就很方便处理了,Example 1.4.1可以改写得比较规范了:
Example 1.4.2
{
"type": "urn:xiot-spec:device:fan:0000A005:zhimi:sa:1",
"description": "Zhimi Fan",
"services": [
{
"iid": 1,
"type": "urn:xiot-spec:service:fan:00007808:zhimi:sa:1",
"description": "Fan",
"properties": [
{
"iid": 1,
"type": "urn:xiot-spec:property:on:00000006:zhimi:sa:1",
"description": "Switch Status",
"format": "bool",
"access": ["read", "write", "notify"]
},
{
"iid": 2,
"type": "urn:xiot-spec:property:fan-level:00000016:zhimi:sa:1",
"description": "Speed Level",
"format": "uint8",
"access": ["read", "write", "notify"],
"value-range": [1, 3, 1]
}
]
},
{
"iid": 2,
"type": "urn:xiot-spec:service:battery:00007805:zhimi:sa:1",
"description": "Battery",
"properties": [
{
"iid": 1,
"type": "urn:xiot-spec:property:battery-level:00000014:zhimi:sa:1",
"description": "Battery Level",
"format": "uint8",
"access": ["read", "notify"],
"value-range": [0, 100, 1],
"unit": "percentage"
},
{
"iid": 2,
"type": "urn:xiot-spec:property:charging-state:00000015:zhimi:sa:1",
"description": "Charging State",
"format": "uint8",
"access": ["read", "notify"],
"value-list": [
{
"value": 0,
"description": {
"en-US": "NOT_CHARGING",
"zh-CN": "没有充电"
}
},
{
"value": 1,
"description": {
"en-US": "CHARGING",
"zh-CN": "充电中"
}
},
{
"value": 2,
"description": {
"en-US": "NOT_CHARGEABLE",
"zh-CN": "不可充电"
}
}
]
}
]
}
]
}
2. 名词和概念
-
Specification
-
规范,简写为spec
-
xiot-spec
-
可扩展IoT规范
-
产品规范
-
所谓的产品规范,指的是对产品功能的基本定义。
-
产品模板
-
所谓的产品模板,指的是对某一类产品的概念定义。
-
产品实例
-
所谓的产品实例,指的是开发者最终的产品功能定义。
-
type
-
全称为Specification Type,即规范定义类型.
-
device
-
设备
-
service
-
服务,也可以理解为功能组
-
property
-
属性
-
action
-
方法
-
event
-
事件
-
instance
-
实例
-
iid
-
全称为instance id,实例id
-
template
-
模板
-
lifecycle
-
生命周期,产品规范定义、产品模板、产品实例都有可能携带这个字段,字段取值含义如下:
| 值 | 含义 | 说明 |
|---|---|---|
| development | 开发中 | 可能随时会修改 |
| preview | 预览中 | 正在测试验证,修改的概率不高了 |
| released | 上线 | 已经测试完成,上线了,再也不会修改了。 |
另外,和汽车工业对比,物联网工业的产品规范、产品模板和产品实例有类似关系:
| 物联网工业 | 汽车工业 | 汽车工业的例子 |
|---|---|---|
| 产品规范 | 零部件规格 | 轮毂尺寸、发动机参数 |
| 产品模板 | 抽象车型 | A级小轿车,B级SUV |
| 产品实例 | 具体车型 | 宝马325,大众途观 |
3. 产品规范
3.1 简介
规范定义,分为:
-
设备规范定义
-
服务规范定义
-
方法规范定义
-
事件规范定义
-
属性规范定义 注: 在规范里,我们称功能组为“服务” 我们需要有一个字段来表达不同的定义,这个字段称之为SpecificationType
3.2 SpecificationType
规范定义类型,简写为 type,必须是URN格式:
urn:xiot-spec:service:device-information:00007801
-
URN表达式
-
URN表达式遵循URN语法规范(RFC2141),6个字段,最后一个字段为可选:
<URN> ::= "urn:"<ns>":"<type>":"<name>":"<value>[":"<vendor>:"<model>":"<version>]
-
urn
-
第一个字段必须为urn,否则视为非法urn。
-
ns
-
名字空间,如果是苹果定义的规范为xiot-spec,蓝牙联盟定义的规范为bluetooth-spec。
-
type
-
SpecificationType (类型,简写为: type),只能是如下几个:
-
template
-
property
-
action
-
event
-
service
-
device
-
-
name
-
有意义的单词或单词组合(小写字母),多个单词用"-"间隔,比如:
-
temperature
-
current-temperature
-
device-name
-
battery-level
-
-
value
-
16进制字符串,使用UUID前8个字符,如:
-
00002A06
-
00002A00
-
-
可以认为value和name是等价的,name字段表达语义,方便人和AI阅读,value使用2个字节,嵌入式设备可以使用value来替代name。
-
vendor
-
厂家,有意义的单词或单词组合(小写字母),比如:
-
philips
-
aux-group
-
注:这个字段在产品规范中不出现,在产品模板和产品实例中出现。
-
model
-
产品型号,有意义的单词或单词组合(小写字母),比如:
-
c200
-
a6
-
mx-5
-
注:这个字段在产品规范中不出现,在产品模板和产品实例中出现。
-
version
-
版本号,只能是自然数,如:
-
1
-
2
-
3
-
注:这个字段只有在产品实例定义里出现。
3.3 设备品类
同一类设备被定义为同一个设备品类,如灯、开关等,使用一个urn表达式来表达:
- type(SpecificationType, 简写为type)
- 设备类型,必须是URN表达式,如:
"type": "urn:xiot-spec:device:fan:0000A005"
- description(描述)
- 对此Device做一个简单的描述:
"description": "风扇"
- 支持多语言:
"description": {
"en-US": "Fan",
"zh-CN": "风扇"
}
3.4 服务定义
服务是一个独立的有意义的功能组,描述一个服务,需要说清楚:
-
是什么服务?
-
有什么方法可以操作?
-
有什么事件可能会发生?
-
有哪些属性?
因此,服务规范定义需要包含如下字段:
- type(SpecificationType, 简写为type)
- 服务类型,必须是URN表达式,如:
urn:xiot-spec:service:fan:00007808
- description(描述)
- 对此Service做一个简单的描述,如:
Fan Service
- 或支持多语言,如:
{
"en-US": "Fan Service",
"zh-CN": "风扇服务"
}
- required-actions(必选方法列表)
- 如:
"required-actions": [
"urn:xiot-spec:action:get-stream-configuration:00000001",
"urn:xiot-spec:action:start-stream:00000101",
"urn:xiot-spec:action:stop-stream:00000201"
]
- optional-actions(可选方法列表)
- 如:
"optional-actions": [
"urn:xiot-spec:action:identify:00002801"
]
- required-events(必选事件列表)
- 如:
"required-events": [
"urn:xiot-spec:event:alert1:00000007"
]
- optional-events(可选事件列表)
- 如:
"optional-events": [
"urn:xiot-spec:event:alert2:00000008"
]
- required-properties(必选属性列表)
- 如:
"required-properties": [
"urn:xiot-spec:property:on:00000006",
"urn:xiot-spec:property:fan-level:00000016"
]
- optional-properties(可选属性列表)
- 如:
"optional-properties": [
"urn:xiot-spec:property:horizontal-swing:00000017",
"urn:xiot-spec:property:vertical-swing:00000018",
"urn:xiot-spec:property:horizontal-angle:00000019",
"urn:xiot-spec:property:vertical-angle:0000001A",
"urn:xiot-spec:property:mode:00000008",
"urn:xiot-spec:property:status:00000007",
"urn:xiot-spec:property:fault:00000009"
]
Example 2.4.1
{
"type": "urn:xiot-spec:service:fan:00007808",
"description": {
"en-US": "Fan",
"zh-CN": "风扇",
"zh-TW": "風扇"
},
"required-properties": [
"urn:xiot-spec:property:on:00000006",
"urn:xiot-spec:property:fan-level:00000016"
],
"optional-properties": [
"urn:xiot-spec:property:horizontal-swing:00000017",
"urn:xiot-spec:property:vertical-swing:00000018",
"urn:xiot-spec:property:horizontal-angle:00000019",
"urn:xiot-spec:property:vertical-angle:0000001A",
"urn:xiot-spec:property:mode:00000008",
"urn:xiot-spec:property:status:00000007",
"urn:xiot-spec:property:fault:00000009"
]
}
解读如下:
-
这是一个风扇服务
-
作为一个风扇,必须有的功能:
-
开关
-
调整风速
-
-
作为一个风扇,可选以下功能:
-
名字
-
旋转
-
旋转角度
-
禁用物理按键
-
当然,服务也可以稍微再复杂一点:
Example 2.4.2
{
"type": "urn:xiot-spec:service:camera:00000007",
"description": {
"en-US": "Camera",
"zh-CN": "摄像头",
"zh-TW": "攝像頭"
},
"required-properties": [
"urn:xiot-spec:property-v2:streaming-status:00000004",
"urn:xiot-spec:property-v2:support-video-stream-configuration:00000002",
"urn:xiot-spec:property-v2:support-audio-stream-configuration:00000002",
"urn:xiot-spec:property-v2:support-rtp-stream-configuration:00000003",
"urn:xiot-spec:property-v2:session-id:00000102",
"urn:xiot-spec:property-v2:controller-ip-version:00000103",
"urn:xiot-spec:property-v2:controller-ip-address:00000104",
"urn:xiot-spec:property-v2:controller-video-rtp-port:00000105",
"urn:xiot-spec:property-v2:controller-audio-rtp-port:00000106",
"urn:xiot-spec:property-v2:selected-video-parameters:00000107",
"urn:xiot-spec:property-v2:selected-audio-parameters:00000108",
"urn:xiot-spec:property-v2:device-status:00000109",
"urn:xiot-spec:property-v2:device-ip-version:00000110",
"urn:xiot-spec:property-v2:device-ip-address:00000111",
"urn:xiot-spec:property-v2:synchronization-source-for-video:00000112",
"urn:xiot-spec:property-v2:synchronization-source-for-audio:00000113",
"urn:xiot-spec:property-v2:session-control:00000119"
],
"required-actions": [
"urn:xiot-spec:action-v2:get-stream-configuration:00000001",
"urn:xiot-spec:action-v2:start-stream:00000101",
"urn:xiot-spec:action-v2:stop-stream:00000201"
],
"optional-actions": [
"urn:xiot-spec:action:set-stream-configuration:00000009"
],
"required-events": [
"urn:xiot-spec:event:alert:00000007"
],
"optional-events": [
"urn:xiot-spec:event:warrning:00000008"
]
}
注意,与Example 2.4.1相比,多了几个字段:
-
required-actions
-
optional-actions
-
required-events
-
optional-events
3.5 方法定义
有时候,一个有意义的操作需要对多个属性进行读写,可以用方法来实现,描述一个方法,需要说清楚:
-
是什么方法?
-
输入参数是什么?
-
方法执行完有没有输出值,如果有,输出值什么?
因此,方法规范定义需要包含如下字段:
- type (SpecificationType, 简写为type)
- 方法类型,必须URN表达式,如:
urn:xiot-spec:action:play:0000280B
- description(描述)
- 对此Action做一个简短的描述:
Get Streaming Configuration Of Camera
- in(输入参数列表)
- 可以是0到N个,每个参数都由属性组成,参数为可变参数,可以重复多次,也可以不出现。
- out(输出参数列表)
- 可以是0到N个,每个参数都由属性组成,参数为可变参数,可以重复多次,也可以不出现。
Example 2.5.1 读取摄像头配置信息(需要一次读取多个属性)
{
"type": "urn:xiot-spec:action:get-stream-configuration:00000001",
"description": {
"en-US": "Get Streaming Configuration Of Camera",
"zh-CN": "从摄像头读取流配置信息",
"zh-TW": "從攝像頭讀取流配置信息"
},
"in": [],
"out": [
{
"type": "urn:xiot-spec:property:streaming-status:00000004",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:support-video-stream-configuration:00000002",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:support-audio-stream-configuration:00000002",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:support-rtp-stream-configuration:00000003",
"repeat": [1, 1]
}
]
}
Example 2.5.2 开启摄像头视频流(需要设置SRTP相关的N个属性,返回SRTP相关的N个属性)
{
"type": "urn:xiot-spec:action:start-stream:00000101",
"description": {
"en-US": "Start Camera Streaming",
"zh-CN": "开启摄像头视频流",
"zh-TW": "開啟攝像頭視頻流"
},
"in": [
{
"type": "urn:xiot-spec:property:session-id:00000102",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:controller-ip-version:00000103",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:controller-ip-address:00000104",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:controller-video-rtp-port:00000105",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:controller-audio-rtp-port:00000106",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:selected-video-parameters:00000107",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:selected-audio-parameters:00000108",
"repeat": [1, 1]
}
],
"out": [
{
"type": "urn:xiot-spec:property:device-status:00000109",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:device-ip-version:00000110",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:device-ip-address:00000111",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:synchronization-source-for-video:00000112",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:synchronization-source-for-audio:00000113",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:session-control:00000119",
"repeat": [1, 1]
}
]
}
哪些情况下使用Action?
对于同时需要对多个属性的读写才能完成一次有意义的操作,用Action,如上文的开启摄像头视频流。
如果对某些属性的写操作很耗时,则用Action,status返回1,待操作完成后再用事件通知。
方法所引用的属性
方法在两种情况下引用到了属性定义,一种是参数列表中的数据,另一种是返回结果列表的数据。
注意:方法只能引用同服务内部的其他属性。
3.6 事件定义
简单的事件,用属性的变化来通知用户。复杂的事件,需要用Event来表达:
-
发生了什么事情?
-
哪些属性发生了变化?
因此,事件规范定义需要包含如下字段:
- type(SpecificationType, 简写为type)
- 事件类型,必须是URN表达式,如:
urn:xiot-spec:event:alert:00000007
- description(描述)
- 纯文本字段,对此事件做一个简单的描述,如:
Get Streaming Configuration Of Camera
- arguments(参数列表)
- 可以是0到N个,每个参数都由属性组成,参数为可变参数,可以重复多次,也可以不出现。
Example 2.6
{
"type": "urn:xiot-spec:event:alert:00000007",
"description": {
"en-US": "alert alert alert!!!",
"zh-CN": "警告",
"zh-TW": "警告"
},
"arguments": [
{
"type": "urn:xiot-spec:property:name:00000002",
"repeat": [1, 1]
},
{
"type": "urn:xiot-spec:property:temperature:00000003",
"repeat": [0, 4]
}
]
}
3.7 属性定义
属性描述需要表达这几个意思:
-
语义是什么?
-
数据格式是什么?
-
是否可读?是否可写?数据变化了是否有通知?
-
值是否有约束?如果有,取值范围是离散值还是连续值?
-
单位是否定义?如果有定义,单位是什么?
因此,属性规范定义需要包含如下字段:
- type (SpecificationType, 简写为type)
- 属性类型,必须是URN表达式,如:
urn:xiot-spec:property:color-temperature:0000000F
- description(描述)
- 纯文本字段,对此事件做一个简单的描述,支持多语言,如:
Name
Temperature
Current Temperature
Temperature Display Units
Battery Level
Air Quality
- format(数据格式)
| 数据格式 | 描述 | 备注 |
|---|---|---|
| bool | 布尔值: true/false 或 1/0 | |
| uint8 | 无符号8位整型 | 建议约束取值范围 |
| uint16 | 无符号16位整型 | 同上 |
| uint32 | 无符号32位整型 | 同上 |
| int8 | 有符号8位整型 | 同上 |
| int16 | 有符号16位整型 | 同上 |
| int32 | 有符号32位整型 | 同上 |
| int64 | 有符号64位整型 | 同上 |
| float | 浮点数 | 同上 |
| string | 字符串 | 建议约束最大长度 |
| hex | 16进制,(使用字符串表示,如”FF0011”, “EE00”等) | 建议约束取值范围 |
| combination | 组合格式,包含多个属性 |
- access (访问方式)
| 值 | 描述 |
|---|---|
| read | 读 |
| write | 写 |
| notify | 通知 |
- value-range (对取值范围进行约束,可选字段)
- 当format为整型、浮点数或hex时,可定义value-range,比如:
| 最小值 | 最大值 | 步长 |
|---|---|---|
| 16 | 32 | 0.5 |
用JSON数组表示:
[16, 32, 0.5]
- value-list (对取值范围进行约束,可选字段)
-
当format为整型,可定义"value-list",每个元素都包含:
-
value
-
description
-
-
用JSON数组表示,如:
[
{"value": 1, "description": "Monday"},
{"value": 2, "description": "Tuesday"},
{"value": 3, "description": "Wednesday"},
{"value": 4, "description": "Thursday"},
{"value": 5, "description": "Friday"},
{"value": 6, "description": "Saturday"},
{"value": 7, "description": "Sunday"}
]
- 描述可以支持多语言,如:
[
{"value": 1, "description": {"en-US": "Monday", "zh-CN": "周一"}},
{"value": 2, "description": {"en-US": "Tuesday", "zh-CN": "周二"}},
{"value": 3, "description": {"en-US": "Wednesday", "zh-CN": "周三"}},
{"value": 4, "description": {"en-US": "Thursday", "zh-CN": "周四"}},
{"value": 5, "description": {"en-US": "Friday", "zh-CN": "周五"}},
{"value": 6, "description": {"en-US": "Saturday", "zh-CN": "周六"}},
{"value": 7, "description": {"en-US": "Sunday", "zh-CN": "周日"}}
]
- unit (单位,可选字段)
- 当format为整型或浮点型,可定义unit值:
| 值 | 描述 |
|---|---|
| percentage | 百分比 |
| celsius | 摄氏度 |
| seconds | 秒 |
| minutes | 分 |
| hours | 小时 |
| days | 天 |
| kelvin | 开氏温标 |
| pascal | 帕斯卡(大气压强单位) |
| arcdegrees | 弧度(角度单位) |
| rgb | RGB(颜色) |
| watt | 瓦特(功率) |
| litre | 升 |
| ppm | ppm浓度 |
| lux | 勒克斯(照度) |
| mg/m3 | 毫克每立方米 |
-
max-length (字符串最大长度) 可选字段,仅当format为字符串时可选。
-
members(成员)
- 可选字段,仅当format为combination时才出现,如:
{
"type": "urn:xiot-spec:property:hsv:00000040",
"description": "HSV",
"format": "combination",
"access": ["read", "write", "notify"],
"members": [
"urn:xiot-spec:property:hue:00000041",
"urn:xiot-spec:property:saturation:00000042",
"urn:xiot-spec:property:brightness:00000043"
]
}
Example 2.7.1 最简单的定义
{
"type": "urn:xiot-spec:property:device-name:00000001",
"description": "Device Name",
"format": "string",
"access": ["read"],
"max-length": 16
}
Example 2.7.2 使用value-range和unit
{
"type": "urn:xiot-spec:property:current-temperature:00000002",
"description": "Current temperature",
"format": "float",
"access": ["read", "write", "notify"],
"value-range": [16, 32, 0.5],
"unit": "celsius"
}
Example 2.7.3 使用value-list
{
"type": "urn:xiot-spec:property:day-of-the-week:00000003",
"description": "Day Of The Week",
"format": "uint8",
"access": ["read", "write", "notify"],
"value-list": [
{"value": 1, "description": "Monday"},
{"value": 2, "description": "Tuesday"},
{"value": 3, "description": "Wednesday"},
{"value": 4, "description": "Thursday"},
{"value": 5, "description": "Friday"},
{"value": 6, "description": "Saturday"},
{"value": 7, "description": "Sunday"}
]
}
4. 产品模板
产品模板,简称模板,在产品模板中,规定了哪些功能是必须的,哪些功能是可选的,同样:
-
在模板的功能里,规定了哪些属性是可选的,哪些属性是必须的。
-
在模板的功能里,规定了哪些方法是可选的,哪些方法是必须的。
-
在模板的功能里,规定了哪些事件是可选的,哪些事件是必须的。
下面是一个具体模板的定义:
{
"type": "urn:xiot-spec:device:lightbulb:00000005:ks:b1:1",
"lifecycle": "preview",
"description": {
"en-US": "Ordinary bulb",
"zh-TW": "普通燈泡",
"zh-CN": "普通灯泡"
},
"services": [
{
"x-required": true,
"iid": 1,
"type": "urn:xiot-spec:service:accessory-information:0000003e:ks:b1:1",
"x-action-addable": false,
"x-event-addable": false,
"x-property-addable": false,
"description": {
"en-US": "Accessory Information",
"zh-TW": "配件信息",
"zh-CN": "配件信息"
},
"properties": [
{
"type": "urn:xiot-spec:property:firmware-revision:00000052:ks:b1:1",
"description": {
"en-US": "Firmware Revision",
"zh-TW": "固件版本",
"zh-CN": "固件版本"
},
"format": "string",
"access": ["read"],
"x-required": true,
"iid": 2
},
{
"type": "urn:xiot-spec:property:identify:00000014:ks:b1:1",
"description": {
"en-US": "Identify",
"zh-TW": "辨認",
"zh-CN": "辨认"
},
"format": "bool",
"access": ["write"],
"x-required": true,
"iid": 3
},
{
"type": "urn:xiot-spec:property:manufacturer:00000020:ks:b1:1",
"description": {
"en-US": "Manufacturer",
"zh-TW": "制造商",
"zh-CN": "制造商"
},
"format": "string",
"access": ["read"],
"x-required": true,
"iid": 4
},
{
"type": "urn:xiot-spec:property:model:00000021:ks:b1:1",
"description": {
"en-US": "Model",
"zh-TW": "型號",
"zh-CN": "型号"
},
"format": "string",
"access": ["read"],
"x-required": true,
"iid": 5
},
{
"type": "urn:xiot-spec:property:name:00000023:ks:b1:1",
"description": {
"en-US": "name",
"zh-TW": "名稱",
"zh-CN": "名称"
},
"format": "string",
"access": ["read"],
"x-required": true,
"iid": 6
},
{
"type": "urn:xiot-spec:property:serial-number:00000030:ks:b1:1",
"description": {
"en-US": "Serial Number",
"zh-TW": "序列號",
"zh-CN": "序列号"
},
"format": "string",
"access": ["read"],
"x-required": true,
"iid": 7
},
{
"type": "urn:xiot-spec:property:accessory-properties:000000a6:ks:b1:1",
"description": {
"en-US": "Accessory Flags",
"zh-TW": "配件屬性",
"zh-CN": "配件属性"
},
"format": "uint32",
"access": ["read", "notify"],
"value-range": [0, 65535,1],
"x-required": false,
"iid": 8
},
{
"type": "urn:xiot-spec:property:hardware-revision:00000053:ks:b1:1",
"description": {
"en-US": "Hardware Revision",
"zh-TW": "硬件版本",
"zh-CN": "硬件版本"
},
"format": "string",
"access": ["read"],
"x-required": false,
"iid": 9
}
]
},
{
"x-required": true,
"iid": 10,
"type": "urn:xiot-spec:service:lightbulb:00000043:ks:b1:1",
"x-action-addable": false,
"x-event-addable": false,
"x-property-addable": false,
"description": {
"en-US": "Light Bulb",
"zh-TW": "燈泡",
"zh-CN": "灯泡"
},
"properties": [
{
"type": "urn:xiot-spec:property:on:00000025:ks:b1:1",
"description": {
"en-US": "On",
"zh-TW": "開關",
"zh-CN": "开关"
},
"format": "bool",
"access": ["read","write","notify"],
"x-required": true,
"iid": 11
}
]
}
]
}
上面的模板中,新出现几个以"x-"字符串开头的字段,表达的是扩展字段:
| 字段名称 | 含义 | 出现的位置 |
|---|---|---|
| x-action-addable | 是否可以添加方法 | service |
| x-event-addable | 是否可以添加事件 | service |
| x-property-addable | 是否可以添加属性 | service |
| x-required | 是否必须实现 | service, property, action, event |
另外,还有几个字段:
| 字段名称 | 含义 | 出现的位置 |
|---|---|---|
| iid | 实例ID,instance id,简称iid | service, property, action, event |
注意,在产品规范中的服务定义中,已经有:必选属性和可选属性、必须方法和可选方法、必选事件和可选事件,产品模板完全覆盖产品规范的内容,更进一步定义了产品概念。
5. 产品实例
产品实例的创建方式:
-
可以继承一个产品模板来创建一个产品实例。
-
也可以直接从产品规范来创建一个产品实例。
5.1 实例ID(Instance ID,简称iid)
对于一个实际生产的物理设备,我们称之为产品实例(Device Instance),每个型号的设备具备的功能应该是一样的。也就是说:
-
Device包含哪些Service是确定的.
-
Service包含哪些Action/Event/Property也是确定的。
所以:在一个产品实例的定义中,可选的东西是不存在的。
在同一个设备中,有可能出现功能重复的定义,比如:
-
插座中有N个插孔
-
净水器有N个滤芯
也就是说:
-
一个Property可能存在多个实例
-
一个Action可能存在多个实例
-
一个Service也可能存在多个实例。
为了区分不同的实例,需要引入一个概念:iid(实例ID)
iid用自然数表示,一个iid在同一级是唯一的,所谓的“iid在同一级唯一”的意思是:
-
在一个Device中,Service的iid是唯一的。
-
在一个Service的properties中,Property的iid是唯一的。
-
在一个Service的actions中,Action的iid是唯一的。
-
在一个Service的events中,Event的iid是唯一的。
注意:iid是自然数,不要求连续增长。
5.2 创建产品实例
在产品实例定义中使用规范定义(Property/Action/Event/Service/Device)时,往往需要修改规范定义。比如:
-
风扇的档位由规范定义的5个档位,修改为10个档位。
-
空调的温度由规范定义的16-32度,修改为15-33度。
因此需要引入一个概念: 继承。 在type字段加上后缀,表示此定义已经被继承,比如:
- 规范定义的属性(speed-level,定义了5个档位)
{
"type": "urn:xiot-spec:property:speed-level:00000023",
"description": "Speed Level",
"format": "uint8",
"access": ["read", "write", "notify"],
"value-range": [1, 5, 1]
}
- 智米做了一款风扇,继承了这个属性,修改风扇的档位为10档
{
"type": "urn:xiot-spec:property:speed-level:00000023:zhimi:aa:1",
"description": "Speed Level",
"format": "uint8",
"access": ["read", "write","notify"],
"value-range": [1, 10, 1]
}
- 奥克斯也做了一款风扇,继承此属性后,修改了风扇的档位为3档:
{
"type": "urn:xiot-spec:property:speed-level:00000023:auxgroup:ff:1",
"description": "Speed Level",
"format": "uint8",
"access": ["read", "write", "notify"],
"value-range": [1, 3, 1]
}
厂家使用继承方式,可以自定义:
-
Device
-
Service
-
Action
-
Event
-
Property
5.2.1 Device
产品实例必须是继承方式,如:
urn:xiot-spec:device:light:0000A001:tuya02:ttt:1
urn:xiot-spec:device:air-conditioner:0000A004:aden:a:1
urn:xiot-spec:device:air-conditioner:0000A004:aux:b:1
urn:xiot-spec:device:outlet:0000A002:chuangmi:hmi:1
urn:xiot-spec:device:outlet:0000A002:chuangmi:m:1
urn:xiot-spec:device:outlet:0000A002:chuangmi:v:1
urn:xiot-spec:device:cooker:0000A00B:chunmi:mmm:1
厂家创建一个设备时,必须实现:
- required-services
可以实现
- optional-services
同时,厂家可以添加其他的service。
5.2.2 Service
在Service实例中,必须实现:
-
required-actions
-
required-events
-
required-properties
可以实现
-
optional-actions
-
optional-events
-
optional-properties
5.2.3 Action
在Action实例中,in和out参数可以被修改。
5.2.4 Event
在Event实例中,argument参数可以被修改。
如果参数被修改,则此Event实例属于继承方式,需要加上后缀字段。
5.2.5 Property
在Property实例中,以下字段都可以被修改:
-
format
-
access (不推荐修改)
-
unit (不推荐修改)
-
value-list
-
value-range
-
max-length
-
members
当然,一般情况下,我们只推荐修改值的约束范围。
特别注意:如果修改了format,则value-list/value-range/max-length等字段也需要跟着调整。
5.3 范例
用一个文件描述整个设备,由于是一个实例定义,所以Service和Property都有自己的"iid"。
- 灯泡实例定义
{
"type": "urn:xiot-spec:device:light:0000A001:vw:cc:1",
"description": "Light",
"services": [
{
"iid": 1,
"type": "urn:xiot-spec:service:device-information:00007801:vw:cc:1",
"description": "Device Information",
"properties": [
{
"iid": 1,
"type": "urn:xiot-spec:property:manufacturer:00000001:vw:cc:1",
"description": "Device Manufacturer",
"format": "string",
"access": ["read"]
},
{
"iid": 2,
"type": "urn:xiot-spec:property:model:00000002:vw:cc:1",
"description": "Device Model",
"format": "string",
"access": ["read"]
},
{
"iid": 3,
"type": "urn:xiot-spec:property:serial-number:00000003:vw:cc:1",
"description": "Device Serial Number",
"format": "string",
"access": ["read"]
},
{
"iid": 4,
"type": "urn:xiot-spec:property:name:00000004:vw:cc:1",
"description": "Device Name",
"format": "string",
"access": ["read"]
},
{
"iid": 5,
"type": "urn:xiot-spec:property:firmware-revision:00000005:vw:cc:1",
"description": "Current Firmware Version",
"format": "string",
"access": ["read"]
}
]
},
{
"iid": 2,
"type": "urn:xiot-spec:service:light:00007802:vw:cc:1",
"description": "Light",
"properties": [
{
"iid": 1,
"type": "urn:xiot-spec:property:on:00000006:vw:cc:1",
"description": "Switch Status",
"format": "bool",
"access": ["read","write","notify"]
},
{
"iid": 2,
"type": "urn:xiot-spec:property:brightness:0000000D:vw:cc:1",
"description": "Brightness",
"format": "uint8",
"access": ["read","write","notify"],
"value-range": [1,100,1],
"unit": "percentage"
},
{
"iid": 3,
"type": "urn:xiot-spec:property:color:0000000E:vw:cc:1",
"description": "Color",
"format": "uint32",
"access": ["read","write","notify"],
"value-range": [0,16777215,1],
"unit": "rgb"
},
{
"iid": 4,
"type": "urn:xiot-spec:property:color-temperature:0000000F:vw:cc:1",
"description": "Color Temperature",
"format": "uint32",
"access": ["read","write","notify"],
"value-range": [1700,6500,1],
"unit": "kelvin"
}
]
}
]
}
6. 产品实例升级
物理设备的固件升级后,可能:
-
仅仅是修复内部bug。
-
增加了设备功能。
对于第1种情况,我们不关心。
对于第2种情况,我们需要规定好升级方式。
比如一款风扇升级过N个固件,更改了3次功能,这3次升级都修改了产品实例的type:
urn:xiot-spec:device:fan:0000A005:vw:cc:1
urn:xiot-spec:device:fan:0000A005:vw:cc:2
urn:xiot-spec:device:fan:0000A005:vw:cc:3
6.1 升级约定
-
升级版本号,需要向下兼容,即:
- 只能添加功能,不能删除和修改旧功能。
-
如果更改了产品型号,则不需要考虑兼容。
-
绝大多数情况下,不建议升级产品型号。
6.2 范例
-
初始版本定义
-
当一个产品刚被创建的时候,版本号是1,如:
{
"type": "urn:xiot-spec:device:fan:0000A005:vw:cc:1",
"description": "Zhimi Fan",
"services": [
{
"iid": 1,
"type": "urn:xiot-spec:service:fan:00007808:vw:cc:1",
"description": "Fan",
"properties": [
{
"iid": 1,
"type": "urn:xiot-spec:property:on:00000006:vw:cc:1",
"description": "Switch Status",
"format": "bool",
"access": ["read", "write", "notify"]
},
{
"iid": 2,
"type": "urn:xiot-spec:property:fan-level:00000016:vw:cc:1",
"description": "Speed Level",
"format": "uint8",
"access": ["read", "write", "notify"],
"value-range": [1, 3, 1]
}
]
}
]
}
-
注意:
- 产品实例中的type是
urn:xiot-spec:device:fan:0000A005:vw:cc:1- 风速被厂家修改了取值范围,type是
urn:xiot-spec:property:fan-level:00000016:vw:cc:1- 两个type的后缀保持一致,都是:
vw:cc:1 -
升级
-
过了一段时间,厂家觉得3档太少,需要升级下固件,支持5个档位。产品实例被修改成:
{
"type": "urn:xiot-spec:device:fan:0000A005:vw:cc:2",
"description": "Zhimi Fan",
"services": [
{
"iid": 1,
"type": "urn:xiot-spec:service:fan:00007808:vw:cc:1",
"description": "Fan",
"properties": [
{
"iid": 1,
"type": "urn:xiot-spec:property:on:00000006:vw:cc:1",
"description": "Switch Status",
"format": "bool",
"access": ["read", "write", "notify"]
},
{
"iid": 2,
"type": "urn:xiot-spec:property:fan-level:00000016:vw:cc:1",
"description": "Speed Level",
"format": "uint8",
"access": ["read", "write", "notify"],
"value-range": [1, 3, 1]
},
{
"iid": 3,
"type": "urn:xiot-spec:property:fan-level:00000016:vw:cc:2",
"description": "Speed Level",
"format": "uint8",
"access": ["read", "write", "notify"],
"value-range": [1, 5, 1]
}
]
}
]
}
-
注意:
- 产品实例中的type是(版本号变成了2):
urn:xiot-spec:device:fan:0000A005:vw:cc:2- 原来的风速属性依旧不变(这是一个在版本1时定义的风速),iid: 2:
urn:xiot-spec:property:fan-level:00000016:vw:cc:1- 新增加了一个风速(iid: 3,版本号是2),档位被调整为5档,type是:
urn:xiot-spec:property:fan-level:00000016:vw:cc:2 -
也就说,在版本2的产品实例中,表达风速的2个属性,都同时存在,都可以进行读和写,向下兼容必须要实现:
-
iid: 2是版本1的产品实例中的风速属性。
-
iid: 3是版本2的产品实例中的风速属性。
-