物联网通讯协议定义原则

tech, engineering practice

Background #

物联网颇有一副崛起之势,但是底层硬件由于功能边界清晰,无涉及复杂业务等原因,很少人在协议抽象和统一标准上下功夫,特别是非标产品,常常陷入能用即可的窘境。

本文是我这一年与硬件打交道的总结。

一个标准成熟硬件的协议抽象 - 充电机 #

充电机标准上,把协议抽象成了四种

“遥” #

物联网之前,人们都是手动离线操作设备,不存在远程控制一说,当充电机的专家聚集在一起商讨远程控制时,强调了此三种抽象后的协议类型皆为”遥”字开头,说明两点:

  1. 中文的博大精深
  2. 协议就是给远程设备使用的,软件行业叫做API,application programming interface,接口。

遥信 #

充电设备的状态信号,充电机能够直接获取的信息,如继电器开关量,系统运行时间等。

遥测 #

充电机需要借助测量设备如电压,电流等。

遥控 #

下控功能

遥调 #

上行调试参数。

充电机协议overview #

这几种协议类型覆盖了充电机常见的使用场景,但是他存在几个问题:

  1. 遥信遥测的定义晦涩暧昧,边界不够清晰。某些数据,在不同的理解下,可以是遥信,也可以是遥测。
  2. 遥调的存在很尴尬,ta的边界更加模糊不清。
  3. 没有专门的故障信息区域用于拓展。

竟然公然表达国标定义不好?其实也不是,毕竟充电机的遥信,遥测,遥控,遥调满打满算,不会超过一千个,而且过去,硬件迭代和拓展速度相对较慢,限制了软件层面的迭代和拓展速度。即使定义的不好,不清晰,也无伤大雅。结果就是,只要协议能用,能满足需求,能跑通即可。

那么紧接着,我们要先澄清既然硬件迭代慢,硬件协议有必要做到高可读,高可扩展,高度抽象吗?

我的回答和立场很明确,ta们都是肯定的。待我展开讨论这两个必要性之后,再切入主题,”物联网底层通讯协议定义原则”

硬件协议有必要做到高可读,高可扩展,高度抽象吗? #

过去的场景

一个硬件设备,卖一次,测试验收一次,由于功能边界清晰,测试场景用例并不复杂多变,而且能够高度重复利用已有测试用例进行横展。

  • 标准化产品,如串口服务器
  • 非标产品,如产线PLC
  • 集成产品,如油车

当下,局势有很大的变化

万物互联的时候,想用一套标准囊括所有需求是不切实际的,那么可扩展性的重要性就开始显现出来。一个硬件设备,卖一次,可能在上到市场之后,还持续的面临多次的迭代。

  • 标准化产品的定制开发部分
  • 非标产品,如定制网关等
  • 集成产品,如电车,换电站

特斯拉,宝马,都持续推出订阅的硬件服务,远程升级提升硬件指标并不是什么新概念。

那么技术上,一套可读,可拓展,的硬件通讯协议,就能够给将来的新功能,新迭代铺路,保证迭代质量。

物联网通讯协议定义原则 #

既然是协议,我们完全可以套用几十年以来,前人总结出来的API设计原则,再加上一些由物联网产生出的特点,来规范我们定义协议的原则。

1. 抽象的原则 #

类似充电机的遥信,遥测,遥控,遥调,我们对硬件设备也需要有特别的抽象,能够将不同类别的信号统一沟通方式和操作流程。

这样做的好处是能够在代码实现上统一规则,有了标准的通讯规则和流程之后,每个人对协议的解读都能统一思想。

以下归类几种常见的抽象方式:

按读写抽象 #

适合对读写严格区分的设备,消防,安全类设备。

抽象方式可类似:

按上报周期抽象 #

适合纯监控系统,电表,温湿度,电池监控,车辆监控系统等。

抽象方式可类似:

按功能抽象 #

具体情况具体分析,适用于功能复杂的设备。

拿机器狗举例:

2. 单一职责 #

每一帧报文只能做一件事。

优点:降低耦合度,报文复用能力强,变更影响小。(高可拓展性)

例:机器狗控制中,假设机器狗完成一个完整的翻跟斗动作,需要准备翻跟斗和翻跟斗两个动作。

❌错误示范

名称描述备注
翻跟斗 1. 圈数; 2. 准备翻跟斗时间(ms) 3. 翻跟斗次数执行全套翻跟斗 = 准备 + 翻跟斗,重复n次

✅正确示范

名称描述备注
准备翻跟斗准备时间(ms)准备翻跟斗
翻跟斗执行翻跟斗

应该分别定义准备翻跟斗动作和翻跟斗两个动作接口。

因为,在将来,或许有一个假动作定义,需要假装准备翻跟斗,但是之后并不会真的执行翻跟斗,我们就能复用准备翻跟斗这个协议了。

拓展使用 - 执行翻跟斗假动作后卖乖

名称描述备注
准备翻跟斗准备时间(ms)准备翻跟斗
翻跟斗执行翻跟斗
卖乖卖乖时间(ms)0

使用方调用三次方法


for (n) {


  * pre execute fangendou(100ms)

  * execute fangendou()

}

* act cute(5000ms)

3. 迪米特法则(最少知识原则) #

每帧报文,不应出现超出职责范围的其它信息。

优点:业务边界明确。(高可读性,高抽象,降低耦合度)

例:机器狗的充电信息监控,不应包机器狗的姿态信号。

❌错误示范

名称描述备注
上报充电信息1. 充电时候的姿态;2. 电流;3. 电压

✅正确示范

名称描述备注
上报充电信息1. 电流;2. 电压
名称描述备注
上报姿态信息1. 身体姿态;2. 耳朵姿态;3. 四肢姿态

4. 接口(报文)隔离法则 #

在一个闭环的交互报文流程过程中,绝不允许耦合任何流程报文之外的其它报文。

优点:业务边界明确。(高可读性,高抽象)

例:控制机器狗的行走结果反馈应该是一个独立的反馈报文,而不是通过其他状态报文上报反馈。

❌错误示范

名称描述备注
开始行走行走距离
名称描述备注
上报姿态信息1. 身体姿态;2. 耳朵姿态;3. 四肢姿态

✅正确示范

名称描述结果备注
开始行走行走距离1. 执行结果(成功|失败);2.失败原因

5. 合并同类项原则 #

不允许一个报文内包含多种语义的类型。

优点:代码复用程度高,开发量低,减少出现bug的可能。(高可读性,高抽象)

例:控制机器狗的行走的控制报文,不应该有修改某个参数的报文。

6. 流程闭环原则 #

每一个下控报文,都要有闭环反馈。

优点:对控制报文统一标准,减少出现bug的可能。(高抽象)

例:控制机器狗行走的报文,无论控制结果如何,都应该有反馈。

7. 统一原则 #

  1. 系统层级,通讯方式,通讯主从关系宜统一。
  2. 系统层级,某一种特定格式的报文类型宜统一。比如所有时间格式统一,字符串大端小端,宜统一。
  3. 对于不同要求实时状态信息的报文周期,应有统一定义。

优点:对状态报文统一标准,减少出现bug的可能。(高抽象)

例:监控机器狗表情状态反馈报文每10ms反馈一次,监控机器狗体温反馈报文,每1s反馈一次。

8. 场景自治原则 #

不应生搬硬套其它场景的协议到不适用的另一个场景。每个场景有每个场景的特点。

优点:对同类报文高度抽象,对不同类报文进行解藕。(高可拓展性,高可读,高抽象)

例:根据实际场景对功能进行抽象,而不是全部强求统一。

9. 下位设备无超时原则 #

超时必然耦合业务,所有超时都应由上位机自行判断。

优点:解藕业务,减少出现bug的可能。