1.前言2.网关的作用3.网关内部进程之间的通信4.网关与云平台的通信5.小结一、前言在上一篇文章中,我们谈到了在嵌入式系统中如何使用MQTT消息总线进行进程间通信。我之前在很多项目中都应用过这种通信模型,通信速度对于非工控产品来说完全够用。我以前做过测试。在x86平台和ARM平台上,一条数据从本地绕到云端,再回到本地,可以控制在毫秒级。上一篇文章只是简单介绍了这样一种设计思路,并没有详细讨论一些细节。这次我们就来说说物联网系统中网关的内部程序应该如何设计。阅读本文后,您可以了解到以下内容:在物联网系统中,设备是如何进行通信的;网关中进程间的消息总线通信模型;网关内部消息总线上的数据如何与服务器通信;作为消遣,了解一些物联网系统的基础知识;2.网关的作用。这个词可以包含所有内容。这样的空话不利于我们的解释,所以我们用一个可以感知和想象的场景来代替,那就是智能家居系统,它是最能代表物联网时代的典型产品。2.1指令转发在一个智能家居系统中,假设有几个设备:这些设备的通信模块,如果是WiFi或者蓝牙,一般可以通过手机直接控制(当然需要厂家提供相应的手机APP),手机相当于一个中心节点,控制着所有的设备。目前市场上部分智能设备采用这种通信方式,如空调、吸尘器、空气净化器、冰箱等,只需在这些设备上加装无线通信模块(例如:ESP8266模块)即可。如果通信模块是其他通信模块,如RF433、ZigBee、ZWave等,由于手机没有这些通信模块,需要网关来“转发”命令。手机和网关都连在家里的路由器上,在同一个局域网。手机将控制命令发送给网关,网关将命令转发给相应的设备。通信模型如下:2.2外网通信在上述通信模型中,手机和网关可以直接通信,因为它们在同一个局域网中。手机不在局域网内怎么办?然后由云端的服务器转发。通信模型如下:手机向服务器发送命令;服务器将命令转发给网关;网关向指定设备发送命令;以上描述的是控制指令的流程,如果是设备发送的告警信息,则数据流向相反。可见,网关是所有设备之间通信的中心节点,也是内网与外网通信的中转节点,即各种智能设备接入互联网的中继。2.3协议转换如前所述,硬件设备上的通信模块都是确定的(RF、ZigBee、ZWave等),一般来说,这些通信模块都可以称为无线通信协议。在智能家居系统中,大部分设备的无线通信协议都是相同的。那么,不同类型的无线通信协议设备能否在同一个系统中共存呢?答案是:是的。只要在网关中集成相应的无线通信协议模块,就可以达到这个目的!如下图所示:从手机APP来看,所有设备都是一样的,并不关心设备的无线通信协议是什么,所以,下发的控制命令是协议无关的。网关收到控制命令后,首先根据命令内容找到目标设备,然后判断目标设备的无线通信协议,最后将命令发送给相应的硬件通信模块,通信模块发送通过无线电信号向设备发出控制命令。从这条指令的传输过程来看,网关起到了协议转换的作用。还有一种通信场景:当系统中的一个“输入”设备与一个“输出”设备绑定/关联时,例如:红外传感器与声光报警绑定:当红外传感器检测到人体时,发送一个信号,进而控制声光报警器发出报警信号;门磁与灯绑定:当门打开时,门磁发出信号,灯自动打开;如果“输入”设备和“输出”设备是不同类型的无线通信协议,还需要网关进行协议转换。2.4设备管理在一个智能家居系统中,可能会有或多或少的设备,对这些设备进行管理也很重要。网关作为系统的中心节点,当然要负责管理设备。设备管理功能包括:设备的添加和删除;设备状态管理(功耗、设备断线、断线等);设备树管理;2.5边缘计算(自动化控制)一般情况下,网关可以通过路由器与服务器保持长连接。如果服务器的处理能力比较强,可以把智能家居系统中需要处理的东西都丢给服务器计算处理,服务器计算后将处理结果发送给网关。看来这个想法是完美的!但是考虑以下两种情况:路由器有问题,网关无法连接到服务器,导致本地数据无法及时上报;系统出现异常,需要紧急处理。如果信息上报给服务器,由服务器计算再回传给网关,所花费的时间可能会超过可容忍的时间,如何处理?(大家可以用车联网系统想象这样一个场景:自动驾驶中的汽车遇到紧急情况,将所有信息上传到服务器,然后等待服务器的下一条指令如何?)对于以上场景,可能是把一些计算和处理操作放在网关端处理比较合适!这也是近几年流行的边缘计算。1.边缘计算是指在靠近物源或数据源头的一侧,融合网络、计算、存储、应用核心能力,提供就近端服务的开放平台。2、应用在边缘侧上线,网络服务响应速度更快,满足行业在实时业务、应用智能、安全和隐私保护等方面的基本需求。3.边缘计算是在物理实体和工业连接之间,或者在物理实体之上。但是,云计算仍然可以访问边缘计算的历史数据。第三,在设计应用程序的体系结构时,可以采用多线程或多进程的方式实现网关内部进程之间的通信。每个人的习惯都不一样。不同,各有各的优势。我们这里不讨论哪个更好哪个更差,因为我更喜欢多进程的设计思想,所以直接按照多进程的程序架构来讨论。3.1网关中需要哪些进程所有需要在网关中执行的进程都是根据网关的功能来确定的,假设包括以下功能:(1)Proc_Bridge网关连接外网的进程需要连接到云端的服务器,这需要一个进程和服务器之间保持长连接,这样才能及时接收到服务器发送的控制命令,并将系统内部的数据及时上报给服务器时间。这个过程需要把从服务器收到的指令转发给网关系统,把从系统收到的信息转发给服务器,类似于网桥的功能,所以命名为Proc_Bridge。(2)设备管理进程Proc_DevMgr该进程用于执行设备管理功能。设备的添加(入网)和删除(退役)都由这个进程管理。(3)协议转换过程Proc_Protocol下行:将应用层的统一通信协议转换成不同类型的无线通信协议,发送给相应的无线模块。上行链路:将设备上报的不同类型的无线通信协议转化为应用层统一的通信协议。(4)边缘计算进程(自动化控制)Proc_Auto显然,这需要一个独立的进程来处理各种计算,这个进程相当于系统的大脑。(5)无线通信协议Proc_ZigBee、Proc_RF、Proc_ZWave相关进程在硬件上。每个无线通信模块通过串口或其他硬件连接与网关的CPU进行通信。因此,每个无线通信模块都需要相应的处理。(6)其他“软设备”进程Proc_Xxx在之前的项目中也遇到了一些硬件设备。它们在逻辑上与门磁、插座等设备处于同一层级,但它们通过TCP连接到网关。对于这样的设备,也可以使用单独的进程进行管理。上述进程在网关中的运行模型如下:3.2MQTT消息总线上述进程之间需要相互通信,不是简单的点对点通信,而是一种网状通信模型。例如:设备管理进程Proc_DevMgr:当任何设备加入系统后,需要对其进行处理,因此需要与Proc_ZigBee、Proc_RF、Proc_ZWave这几个进程进行通信;当设备上报数据时(例如:Proc_ZigBee),Proc_Protocol进程需要对数据进行协议转换,然后Proc_Bridge进程将转换后的数据上报给服务器,Proc_Auto进程需要检查设备上报的数据是否正确。设备触发其他相关设备;通信相互交叉,通过传统的IPC方式(共享内存、命名管道、消息队列、Socket)等处理起来比较复杂,引入MQTT消息总线后,每个进程只需要安装在总线上。每个进程只需要监听自己感兴趣的话题,就可以接收到相应的数据。由于这些进程之间的通信关系比较复杂,一个好的题目设计规范就显得非常重要了!3.3主题设计MQTT通信模型是基于订阅/发布模型,一个客户端(进程)访问消息总线后,需要注册你感兴趣的主题topic,其他客户端(进程)发送消息给这个主题,可以被订阅者接收。Topic主题是由反斜杠(/)分隔的字符串,用于表示多层层次结构。例如,以下两个主题是与亚马逊AWS平台中的在线升级(OTA)相关的主题:$aws/things/MyThing/jobs/get/accepted$aws/things/MyThing/jobs/get/rejected在我们的示例场景中,topic主题可以设计如下:(1)Proc_DevMgr订阅主题:$iot/v1/ZigBee/Register$iot/v1/ZigBee/UnRegister$iot/v1/RF/Register$iot/v1/RF/UnRegister$iot/v1/ZWave/Register$iot/v1/ZWave/UnRegister(2)Proc_Bridge订阅主题:$iot/v1/Device/Report发送数据的主题:$iot/v1/Device/Control$iot/v1/Device/Remove$iot/v1/Auto/AddRule$iot/v1/Auto/RemoveRule(3)Proc_Protocol订阅主题:$iot/v1/Device/Control$iot/v1/Device/Remove$iot/v1/ZigBee/Report$iot/v1/RF/Report$iot/v1/ZWave/Report发送数据主题:$iot/v1/Device/Report$iot/v1/ZigBee/Control$iot/v1/ZigBee/Remove$iot/v1/RF/Control$iot/v1/RF/Remove$iot/v1/ZWave/Control$iot/v1/ZWave/Remove(4)Proc_Auto订阅主题:$iot/v1/Auto/AddRule$iot/v1/Auto/RemoveRule$iot/v1/设备/报告服务nd数据主题:$iot/v1/Device/Control(5)Proc_ZigBee订阅主题:$iot/v1/ZigBee/Control$iot/v1/ZigBee/Removesenddata主题:$iot/v1/ZigBee/Register$iot/v1/ZigBee/UnRegister$iot/v1/ZigBee/Report(6)Proc_RF订阅主题:$iot/v1/RF/Control$iot/v1/RF/Remove发送数据主题:$iot/v1/RF/Register$iot/v1/RF/UnRegister$iot/v1/RF/Report(7)Proc_ZWave订阅主题:$iot/v1/ZWave/Control$iot/v1/ZWave/Remove发送数据主题:$iot/v1/ZWave/Register$iot/v1/ZWave/UnRegister$iot/v1/ZWave/Report上面这些题目的设计还是有些粗糙。如果使用通配符(#、+、$),可以设计出更灵活的层次结构。多级通配符:“#”是一个通配符,用于匹配主题中的任意级,多级通配符代表其父级和任意数量的子级。单级通配符:“+”加号是只能在单个主题级别匹配的通配符。单级通配符可用于主题过滤器的任何级别,包括第一级和最后一级。通配符:“$”表示匹配一个字符,只要不放在主题的最开头,其他情况下表示匹配一个字符。下面以一个控制命令为例,梳理一下数据是如何流经主题的:Proc_Bridge进程收到服务器的控制命令后,通过消息总线发送给主题:$iot/v1/Device/Control。由于Proc_Protocol进程订阅了该主题,因此指令会立即收到。Proc_Protocol分析命令内容,发现是ZigBee设备,然后进行协议转换,在消息总线上向主题:$iot/v1/ZigBee/Control发送ZigBee控制命令。由于Proc_ZigBee进程订阅了这个主题,它收到了这个控制命令。Proc_ZigBee将控制命令转换成ZigBee无线通信模块需要的格式,通过硬件发送给设备灯泡。我们再分析一下设备数据上报的场景:首先注意图中的红色箭头,忽略蓝色箭头:门磁打开后,通过无线通信将信息上报给进程Proc_CF。Proc_RF进程接收到RF433通信模块上报的数据,将“门磁打开”的信息发送到消息总线上的主题:$iot/v1/RF/Report。由于Proc_Protocol进程订阅了这个主题,它接收到上报的门传感器数据。Proc_Protocol对数据进行解析,将RF433协议的数据转换成统一的应用层协议的数据,发送到消息总线上的主题:$iot/v1/Device/Report。由于Proc_Bridge进程订阅了这个主题,它收到了上报的数据。Proc_Bridge进程将数据报告给服务器。我们再看一下蓝色箭头的流程:在上面的第4步中:Proc_Protocol流程将RF433协议数据转换为统一的应用层协议后,将数据发送到消息总线上的主题:$iot/v1/Device/Report,Proc_Auto进程同时执行以下操作:5.由于Proc_Auto也订阅了这个主题,所以它也接收到门磁上报的这个应用层协议的数据。6、Proc_Auto查找自身的配置信息(假设用户预先配置了一个规则:当门磁打开时,会触发声光报警),发现规则“门磁->报警”是匹配的,所以发出控制报警的命令,发送到消息总线上的主题:$iot/v1/Device/Control。下面的7、8、9、10这四个步骤和上面的控制命令流程完全一样。3.4与DBUS总线的对比从上面描述的三种数据流场景,你觉得使用topic作为“数据管道”的通信方式是不是特别类似于Linux系统中的DBUS总线?DBUS总线也用于进程间的通信,根据我个人的理解,DBUS实际上组织了两种进程间的通信:基于信号的数据传输;基于方法的RPC远程调用;DBUS总线中包含的概念比较复杂一些,包括:路径、对象、接口、方法等。这些概念被组织在一起,共同定位到一个特定的服务提供者。相比之下,我觉得MQTT的方式更加简洁。所谓RPC远程调用就是调用远程机器上的一个函数,主要解决两个问题:网络连接;数据的序列化和反序列化;后面会写一篇文章,使用protobuf框架实现RPC调用。四、网关与云平台的通信上面讲解的设计过程就是网关内部各个功能模块之间的通信方式,这也是我们作为嵌入式开发者可以充分发挥的部分。网关与云平台的通信方式一般由客户指定,只有少数几种(阿里云、华为云、腾讯云、亚马逊AWS平台)。一般要求网关与云平台处于长期连接状态,以便随时向网关发送来自云端的各种指令。当然,这些云平台都会提供相应的SDK开发包,一般更多的是使用MQTT协议来连接云平台。在一些文档中,位于云端的MQTT服务器被称为Broker,它实际上是一个服务器。Proc_Bridge进程的作用主要有两点:与云平台的数据传输通道;协议转换:将云平台相关协议转换为网关内部协议,反之亦然。也就是说:Proc_Bridge进程需要同时连接到云平台的MQTTBroker和网关内部的MQTT消息总线。在下一篇文章中,我们将具体讲解这部分内容,并提供实现桥接功能的代码模板。五、总结作为一名嵌入式软件开发人员,如果只根据别人设计的框架来填写代码,时间长了会觉得有点累,不知道技术提升的方向在哪里。仔细想想,其实有很多方向:Linux内核、文件系统、算法、应用程序设计等等。本文讨论的内容不是架构设计,只是各个功能的简单通信模型物联网网关内的模块。如果你有机会设计类似的产品,不妨试试这种沟通模式,当然你会设计得更好!本文转载自微信公众号“IOT物联网小镇”,可通过以下二维码关注。转载本文请联系物联小镇公众号。
