大体上来说,一个典型的物联网项目主要由云、管、端三大部分组成。
上图展示了一个典型物联网项目的组件。
其中,终端是多种软硬件的集合,它是带有感知、控制、通信等能力的智能硬件。
管道是物联网的网络基础,通信方案是物联网管道的硬能力。除此之外,具体通信方案的实现需要合适的协议以及规则,也就是网络协议。协议是物联网管道的软能力,它们保证了不同应用场景的通信效率和安全。
云端是物联网的大脑和中心,大致可分为服务层和应用层。服务层提供基础、通用的服务,负责维护物联网终端设备的接入;存储、分析、处理终端数据;提供物联网通信的安全保障;同时提供智能、快速的运算能力。在服务层提供的基础功能之上,应用层实现具体业务,比如共享单车、智能家居系统、智慧农业系统,等等。
它向上承接了互联网,向下统领了嵌入式硬件开发的一个承上启下的全栈开发技术。
虽然我们并不能预测物联网技术栈最终的样子:统一的开发语言是 JavaScript 还是 Python 亦或者其他编程语言;HTTP、WebSockets、MQTT、CoAP 等协议谁会是最后的赢家,并且随着物联网的不断进化,甚至我们可能都无法预测其最终形态,也许根本就没有一个最终的形态。但是,我们仍然可以看清物联网发展的轨迹与必然趋势——开发技术栈必然向全栈化方向发展。
互联网的核心是数据的流动,数据的流动为我们带来了难以想象的价值,而物联网又将这一核心推到了更高的高度,打破了互联网原有的边界让千千万万节点设备中的数据流动了起来。全栈化的开发正是顺应了这种趋势,打破了在开发层面中那些阻碍数据流动的技术壁垒,将芯片、嵌入式、网络、大数据、人工智能、信息安全等诸多领域纳入到物联网的全栈开发中来,实现端到端的完整解决方案,真正实现数据的流动并让数据为人类服务,让我们以更高效更智慧的方式来发掘数据的价值,实现数据的价值。
不管是从商业模式导出的业务模型,还是从技术发展的角度看,文本都倾向于将物联网技术构架看作是互联网技术构架的延展。而与这个观念对立的,是传统嵌入式软件开发的视角。
简单来说,目前的互联网技术构架主流是大前端与后端两个世界:大前端包括 Web 的 JavaScript 技术、Android 和 iOS 技术,着眼于解决用户交互;后端包括数据库、服务构架、运维等,着眼于解决存储、业务逻辑、安全与效率等。当然,现在前后端技术争相更新,比如业务逻辑前置化、微服务构架、JavaScript 全栈化等新的解决方案也开始模糊前后端的差异。而物联网设备端的引入,着实让这些技术有点难以归类,从业务性质上物联网是另外一种前端或是前端的延伸,比如共享单车应用中,自行车端的应用显然是跟人交互的另一个业务场景,也在为后端源源不断地提供着数据,但是自行车又不像网页或者 App 完全是在解决可视化 UI 的事情。而且,现在的设备端开发技术跟前端技术太不像了,由于目前设备端的开发技术都还偏底层,一般来说计算资源如处理能力、本地存储都非常有限,反而像后端一样要考虑资源效率。
那么,我们只好为物联网单独命名一个端,不如我们暂时就叫它设备端。
图1 整体架构图
新后端
MQTT
新后端核心问题在于加入了面向设备的接入服务,实际上在这里,除类似视频对讲或是安防监控的多媒体实时通道外,这个接入服务已经基本事实化为 MQTT。
消息队列遥感传输协议是在TCP/IP协议之上使用的,基于发布/订阅的“轻量级”消息协议,目前为 ISO 标准(ISO/IEC PRF 20922)。它被设计用于轻量级和低带宽的远程连接,发布/订阅消息传递模式需要消息代理,消息代理负责根据消息的主题向需要的端发布消息。
如果需要连接的设备没有超过10万台,使用 8GB 内存的云主机跑 Mosquitto 就可以;如果设备量是几十万台,可以考虑 Mosquitto 做集群负载均衡;如果设备量是大几十万台乃至百万台以上,那你需要专业的团队或专门的投入来维护这件事情,这个细节就不在本文讨论范围了。
OTA
固件组件在线升级是必须要做的事情,MQTT传 大文件不靠谱,所以一般传过去一个带 Token 的 URL,设备端去下载就好,HTTP 或者 HTTPS 都可以。业务比较简单,设备端几十万以内没有什么特别的地方。
数据存储与服务
Mosquitto 作为 MQTT 的引擎,需要后端按照业务逻辑去调用,这里按照业务需求写好后端逻辑即可。在各种后端语言中调用 Mosquitto 都非常简单。
设备端
设备端是物联网领域最五花八门并且正在发展中的地方。其他领域,后端或者前端,经过十几年的发展,已经出现每个细节的主流技术,基本没有碎片化的情况,但是在设备端,开发技术的碎片化是应用发展还不到位的充分表现。举例讲,选用不同的芯片,就要用不同的操作系统,不同的 C 库封装,各家 IDE 也不尽相同,编译工具链更是从芯片原厂给出。开发起来呢,寄存器、内存分配、硬件中断都要深入进去。这就是传统嵌入式开发的现状,也是物联网设备端开发的现状。
到目前为止,真正生产环境中用到的语言就是 C/C++,极个别会在设备端用到 Python,基本没有其他语言。操作系统超过50种,主流的也有10种以上,其中嵌入式 Linux 份额并不大,各种实时操作系统各具特色,各有一片天地。
简单总结一下相对于物联网开发,传统嵌入式开发的方式主要有以下几个问题:
需要考虑中断、寄存器、内存分配等过于底层的工作;
编译、烧写、观察、借助调试设备进行调试的开发生命周期;
不同 SoC 和系统的差异过大;
缺乏代码复用与开源的习惯;
开发者在开发环境和固件编译上花费的时间过多。
所以我们看到设备端的开发是基于芯片选型完成的。当设备端产品面临一个需求时,现有的流程是判断产品的各项技术参数,从而确定一个芯片,进而使用这个芯片的一整套开发技术。这也是早期嵌入式场景使用的芯片自生技术特性所决定:计算资源(CPU 主频、存储)、外围接口、使用温度、通讯协议等核心参数的不同导致芯片碎片化,芯片碎片化导致嵌入式开发碎片化。
目前这个领域的大趋势是:物联网芯片有望走向趋同,物联网开发环境与技术有望趋同。
物联网芯片
早期由于成本所限,物联网领域使用的芯片总是表现得非常缺资源,很难找到一个各方面(计算资源、外围接口、使用温度、通讯协议等)都比较合适的芯片去适应普遍的场景。随着半导体门槛逐步降低,中国半导体制造业逐步成型,芯片资源开始走向富余,其中的代表芯片是 MTK 的 MT7697、MT7688 和乐鑫的 ESP32。
MT7697 主要参数为:ARM Cortex M4 CPU,带浮点单元,最大主频 192Mhz,内存为 256KB SRAM,可配置 4MB 以上的存储空间,芯片内嵌 WiFi 和 BLE 4.2,有足够的外围接口,并能够适应工业级的使用温度。
MT7688 主要参数为:MIPS 580Mhz CPU,内存最大支持 256MB,可配置 16GB 级别的存储空间,芯片内嵌 WiFi,接口除模拟接口之外数字接口丰富,价格在几十元人民币,功耗较高不适于电池长期使用。但是非常有优势的是其提供的 Linux 开发环境,能够让开发者有一种在普通 x86 机器上使用 linux CLI 的体验,Node.js、MySQL、OpenCV、Nginx 等等在阿里云上怎么用,在这个几十块的物联网小模块上也怎么用。稳定性超强,几年不死机也是正常的。
ESP32 的主要参数为:Tensilica LX6 CP,主频 240 MHz,内存为 520KB SRAM,可配置 4MB 以上的存储空间,芯片内嵌 WiFi 和蓝牙以及 BLE,有足够的外围接口,并能够适应工业级的使用温度。
这几颗芯片共同的特征是计算资源和通讯能力以及接口资源相对于传统 MCU 来说有足够的富余,并保持在同样的价位。因此,在这类芯片上,有足够的资源做抽象化的封装和开发框架实施。我们看到除了这几颗芯片原厂提供的传统嵌入式开发包之外,社区和其他厂商已经在这几颗芯片上加快了新开发技术的实现。
开发技术
物联网设备端开发技术目前有两个比较大的发展方向,一是统一化的物联网操作系统,二是统一化的物联网开发框架。他们共同的目的是形成“软件定义物联网”,与传统从芯片选型开始的,着陆于原厂 SDK 中完成应用开发,与需求和产品设计汇合的流程完全相反,希望从需求和产品设计入手,通过公开统一的软件构架完成开发,再根据开发使用到的资源去落地芯片和外围设备。这样做的好处主要在于提高开发效率和形成可以复用的应用代码。
操作系统
虽然市场上存在的设备端操作系统有数十种之多,但是我们看到活跃的,明显向“软件定义物联网”方向发展的有三家:
Zephyr
Zephyr 是 Linux 基金会于2016年2月发布的物联网操作系统,背后主要的支持力量来自于 ARM 和 Linaro,具有目前嵌入式小型实时操作系统的普遍特征,比如:轻量到 KB 级的最小系统内存占用,支持多种芯片构架:从 ARM Cortex-M、Intel x86、ARC(DSP 内核)、NIOS II(FPGA 软核)到开源的 RISC V 等,跟 Linux 一样的模块化内核组织方式,如图2所示。
Zephyr 目前已经升级到 V1.7 版本,逐步向一个可以用到生产环境的系统靠拢了。Zephyr 最大的特色并不在于其完备性而在于其开发理念完全来自于“软件定义物联网”,并且有很好的资源支持,在未来应该会有自己的位置。
图2 Zephyr 物联网操作系统
RTthreadRTthread 是纯国产的小型操作系统,植根于中国的各种使用场景,10年来已经确立了自己的地位,在很多行业有自己的一席之地,目前社区非常活跃,核心团队以创业公司的形式推进,非常专注。技术上的特征作为一个成熟的系统,没有什么可以吐槽的地方。Zephyr 有的技术优势 RTT 都有,而且 RTT 在生产环境的装机量较为可观。
华为 LiteOS
华为是全球范围内物联网技术的根源厂商之一,LiteOS 是一个华为内部很多产品都在用的系统,目前也以开源的形式在全力推广。LiteOS 最大的优势在于华为很多根源技术将利用 LiteOS 进行输出,目前最大的例子就是即将全面商用的 NB-IoT 技术,设备端的开发包将会用 LiteOS 输出。
以上几个系统一致的特点包括小型化、芯片适应范围广、通信协议适配比较广泛等,他们也都是开源的系统,研发或推动力量比较活跃。有可能在物联网领域里的类似 Linux 地位的主流操作系统会是其中某个,也或许会一直都存在下去但是在技术上越来越趋同。
开发框架
首先解释一下开发框架,开发框架可以小到是一个细节的工具,也可以大到规定开发的全部边界。最典型的例子是 Android,纯粹操作系统意义上,Android 是 Linux 的一个分支,但是从 App 开发角度,除 NDK 之外,没有任何与 Linux 打交道的地方,所以也把 Android 叫做操作系统。再广泛地看,Android 除了面向手机应用的开发框架,还准备了 Google play 这样的应用分发渠道,这是开发者生态建设。同理,我们看 Node.js 在后端的种种开发模式,也是将所有后端资源都封装到 JavaScript 里,开发时可以随时 npm install 各种包来 require,解决了代码复用问题。
因此我的观点是,开发框架以及背后的代码复用和开发者生态才是真正的操作系统。
目前在物联网领域,正在尝试向生产环境演进的开发框架基本都基于 JavaScript,而在小型实时操作系统上使用的 JavaScript runtime 目前也基本集中到了 JerryScript 上。JerryScript 是三星开发和开源的一个小资源占用的引擎,内存需要 64KB,存储需要 200KB 即可,能够实现完整的事件驱动,符合 ECMAScript 5.1。
如同前文所说,开发框架或是操作系统在当下需要包括以代码复用为目的的开发者生态,甚至需要包括应用分发,所以我们看到在 JerryScript 的基础上,有两家做这类工作的团队值得关注:
WRTnodeWRTnode 是一个北京的开源硬件团队,提供从开发到硬件交付的全流程服务。他们最近开放的 node.system 和 noyun.io 即是着眼于实现物联网 JavaScript 的开发框架和开发者生态。在 WRTnode 的实现里,设备端的 JavaScript 开发已经变得像 cloud9.io 一样全案在线开发,为开发者屏蔽了嵌入式开发的繁琐编译烧写工作。
RuffRuff 是位于上海的创业公司,2015年开始一直在演进基于物联网设备端 JavaScript 的开发者生态,提供了较为可行的代码复用框架。目前他们已经开始服务商业客户,为物联网应用的快速实现提供了可能。
同时,Zephyr 和华为 LiteOS 也都有各自的 JavaScript runtime 发布计划。
以上我们看到了设备端开发的一些新的发展,目前这些新的设备端开发技术,已经逐步面向交付转移了。有理由相信经过一段时间的发展,面向效率的商业模式驱动下的物联网开发技术将迎来一大波更新,从而导向物联网应用的真正大发展。
基于 JavaScript 语言的快速物联网开发架构
随 JavaScript 语言的流行,及物联网领域的崛起,我们能看到它们结合的可能性,同时也发现它特别适合于物联网开发。因此,在这篇文章里,笔者将主要从以下三个方面进行介绍:
典型的物联网架构,及多种语言带来的问题;
只使用 JavaScript 语言的物联网架构;
详解基于 JavaScript 语言的物联网不同层级结构。
那么,先让我们看看典型的物联网架构是怎样的吧。
典型的物联网架构
我们甚至还可以认为,物联网只是对互联网的扩展。与传统的 C/S 架构相比,它多了一个“数据采集层”,我们称之为传感器层、硬件层等。数据的产出不再只是用户,还来自于各式各样的联网设备。物联网不再局限于使用 HTTP 协议来传输数据,它还会使用 CoAP(受限制的应用协议)、MQTT(消息队列遥测传输)协议。
物联网的四个层级
当前的物联网应用,所要做的就是控制和数据处理。指令,由用户到终端一层一层往下下达,直到硬件端由设备去执行。而数据,便是一层一层往上上报,直至被可视化。
因此,与互联网的架构相比(如图1、图2所示),起点与终点不一样了:指令的终点与数据的起点,变成了硬件层,而非最后的用户层。
图1 互联网架构
图2 典型的物联网架构
数据由客户端 A 发送到服务端,客户端 B 再从服务端获取 A 的数据,如此便算是完成了一个回路。而物联网架构则稍微麻烦了一些,多了一个层级,便多了一个步骤。
硬件层上的微控制器通过直连的方式,采集各式各样的数据,比如温度、湿度等。而受限于微控制器的成本、环境条件等因素,它可能无法直接连接到互联网。因此,需要连接到一些额外的联网设备才能实现。
而这些联网设备,会负责处理来自各个硬件设备的数据,并将其上传至服务器。同时,它会提供一个无线(如蓝牙、红外、ZigBee)接口作为数据的入口。因此,这一层级需要有更好的数据处理能力,并且它应该要可以快速开发。因为这些设备主要做的是协调工作,我们习惯于将其称为“协调层”。
使用多种语言的物联网
多年以前,笔者曾做过一个并不复杂的物联网系统:
使用 Python 里的 Django 作为 Web 服务框架,Django REST Framework 创建 RESTful API;
为了使用手机作为控制器,还用 Java 写一个 Android 应用;
使用 Raspberry Pi 作为硬件端的协调层,用于连接网络,并传输控制信号给硬件;
在硬件端使用 Arduino 作为控制器,写起代码特别简单;
还使用了 ZigBee 模块 XBee 及 I2C 作为连接不同 Arduino 模块的介质;
最后,还需在网页上做一个图表来显示实时数据。
为此,我们需要使用 Python、Java、JavaScript、C、Arduino 五种语言。而如果我们要写相应的 iOS 应用,还要用到 Objective-C。对于其他物联网项目来说,也多是如此,这简直是一场灾难。
在做这样的物联网项目之前,我们需要找到六个不同类型的工程师:一个硬件工程师设计电路图,一个懂硬件的嵌入式工程师,一个写服务端应用的工程师,一个写 Web 前端的工程师,以及对应的 Android 和 iOS 工程师。
且不考虑系统本身的协作,要找到这么多的工程师就不是一件容易的事。而如果我们可以只使用一种语言,将大大地改善开发效率、开发人员的难题。
JavaScript 语言下的物联网架构
JavaScript 语言在最近几年里特别流行,它流行起来有很多个原因,如:
使用 WebView 开发 UI 效率更高,也因此使得WebView 随处可见;
基于事件驱动的编程模型;
JavaScript 容易上手(这是优点,也是缺点);
也因此,React、Unity 等框架提供了更多的可能性,可以让开发者用 JavaScript 开发游戏、VR 应用等等。
那么,只使用 JavaScript,我们可以设计出怎样的物联网系统呢?
基于纯 JavaScript 的物联网架构
如上所述,几年前要想寻找一门能完成一个包含客户端、服务端的系统的语言可谓相当地困难。而随着客户端(浏览器、移动设备)性能的提升、Node.js 的出现,这样的语言就浮现了出来,即 JavaScript。它不仅可以让我们只用一门语言来降低开发成本,还能实现快速地开发出这样的一个系统。那么,剩下的问题就是,在不同的层级,如何选用合适的框架来实现快速开发。
如图3所示,我们可以看到不同层级的可选用 JavaScript 方案。在此之中,有些纯粹只是为了证明 JavaScript 是可行的;有一些则可以在开发效率与运行速率上达到最好的平衡。选用这些方案,可以让我们实现更快速的 JavaScript 物联网应用开发。
图3 基于纯 JavaScript 的物联网参考架构
服务层
对于服务层来说,自主开发的物联网服务端,主要采用的是基于 Node.js 的方案。然而,我们发现有越来越多的应用,在使用 Serverless 的架构,不仅可以快速推出一个可用的原型,未来也能够轻松地基于这个原型来添加业务功能。
图4 物联网服务层
图4便是我们看到的物联网服务层的三种方案:
自主开发:即遵循传统的服务端开发模式,定义自己所需要的功能;
使用云服务:直接使用成熟的物联网云服务,它们在云端集成了各种所需要的功能;
Serverless:Server 可以看作是在云服务之上的自主开发,集两者之便利。每一种方案都有各自的特点,也适合于不同开发能力的项目。但如果要实现快速的开发,那么理想的方式便是采用 Serverless 架构模式。
自主开发
出于不同的原因,诸如保密、安全、可扩展、核心技术等原因,一定规模的公司会采用自主开发的方式。这种开发方式与 Web 应用开发方式并没有太大区别,都是在数据进行 CRUD 操作。并且和前后端分离架构一样,使用 API 作为接口,同时再加上支持不同的传输协议,如 MQTT、CoAP 等。
图5 Lan 物联网架构
如笔者之前在 GitHub 上开源的 Lan(https://github.com/phodal/lan),便是一个精简的物联网服务端示例。基于 Node.js 与 MongoDB,其架构如图5所示。
采用传统的关系型数据库来存储用户信息;
采用 NoSQL 可以应对不同的传感器数据;
提供 UI 界面供管理人员管理用户;
在协议上提供 HTTP、CoAP、MQTT、WebSocket 等的支持,方便不同的类型适配。
除此,物联网系统在存储上,采用 NoSQL 作为存储介质会有更大的优势。一般来说,物联网系统的数据都是写入远远多于读取的场景。与此同时,由于设备的种类繁多,不可能为每一类设备创建表;或者考虑到大量设备的特性,来建立一个通用的表,但在未来这样的表可能仍不适用。
因此,对于物联网数据来说,选用诸如 MongoDB 这一类的 NoSQL 数据库,有这么一些优点:
灵活性。采用非结构化的数据模型,可以存储和处理任何结构的数据;
支持水平扩展。NoSQL 数据库的分布式存储架构,带来了优秀的水平扩展性;
实时数据分析。如 MongoDB 可以通过丰富的索引和查询支持,包括二次、地理空间和文本搜索索引,聚合框架和本地 MapReduce,可以针对传感器数据就地运行报告分析。
然而,这样的系统不免存在研发周期长的问题。如果需要快速验证,那么应该考虑使用云服务来完成部分功能。
物联网云服务
对于硬件团队来说,直接使用云服务是一种更简单、快速的搭建物联网系统的方法。而使用物联网云服务,就意味着:我们可以直接上硬件层的传感器数据,并在应用层获取、分析这些数据。这一类的服务,比较成熟的有 AWS IoT Things(如图6所示)、Azure IoT 等。
图6 AWS IoT Things 参考架构
基于 AWS IoT Things,我们只需要在云端,定义好对应的数据处理规则,便可以在硬件端直接对接服务。不过值得注意的是,单一的云服务无法提供复杂的功能,这个时候就需要一些搭配额外的服务。
Serverless
Serverless 架构(如图7所示)是云服务的一种,但是它在可编程与云服务之间做了一个折中。它是一种基于互联网的技术架构理念,应用逻辑并非全部在服务端实现,而是采用 FaaS(Function as a Service)架构,通过功能组合来实现应用程序逻辑。
图7 Serverless 物联网参考架构
从理论上来讲,这些服务提供的是一层 API 封装,它不会限制我们所使用的语言。使用 Serverless 服务,我们可以具备更好的快速开发能力,并且能使用同一种语言(JavaScript)来完成编程。
在这个过程中,开发者要所做的便是:在不同的服务之间传输数据,每一次都只处理下一个服务所需要的数据,类似于 Pipe and Filters 架构模式。如一个典型的物联网应用的数据传输过程中是这样的:
对设备进行鉴权;
转换、存储设备的数据;
广播通知其他监听此设备数据的服务;
后台查询数据;
分析数据(AI);
可视化数据。
只需要少量的编程,我们就可以完成服务端的开发。随后,专注于硬件层的开发,以及应用层的业务功能。
应用层
在应用层方面,已经有大量的地方使用到了 JavaScript。除了传统的桌面浏览器,还有更多的领域也可以用 JavaScript 来开发。比如移动应用,已经有基于 Cordova + WebView 的成熟方案,还有近两三年流行起来的 React Native,都可以让开发者使用 JavaScript 完成物联网移动应用的开发。又如微信小程序,可以直接用蓝牙来连接硬件设备,也是使用 JavaScript 来编程。
因此,就目前的 Web 趋势来看,在应用层,JavaScript 将是快速开始的主流选择。
在日常中的应用中,我们可以发现物联网的应用层,经常作为协调装置来连接硬件,并上传应用的数据。诸如共享单车、智能手环应用等,它们既通过蓝牙来获取数据,又上传数据到服务端。与此同时,有相当多的应用是运行在桌面客户端上的。故而在这一层级的应用,可谓是种类繁多。
今天,开发人员在做移动端的技术选型时,都会优先考虑到跨平台能力(Android、iOS)。而在这些跨平台框架里,混合应用框架 Cordova(WebView)和 React Native 是使用最为广泛的两个框架,且它们都是使用 JavaScript 作为核心开发语言。
Cordova 是使用 WebView 来渲染页面的。因此与 Reavt Native 相比,使用 Cordova 的最大优势是,可以复用已有的 Web 前端应用的逻辑,并且有大量的图表工具可以直接使用——这一点在物联网应用中特别重要。而在混合应用框架中,Ionic 是这个领域使用最多的 UI 框架。
React Native 使用原生组件来渲染 UI 组件,不仅可以解决 Cordova 饱受诟病的性能问题;同时,它还能嵌入 WebView,解决一些复杂的图表显示问题。
但是如果只能蓝牙的交互,可以考虑 PWA 或微信小程序。运行在 Chrome 浏览器上的 PWA 应用,可以直接使用 Web Devices API,如Bluetooth、NFC、USB,即在浏览器上直接调用原生接口,并实现对设备的控制。而诸如最近一年内流行的微信小程序,则也可以访问蓝牙、GPS、罗盘、加速度计等硬件接口,同时用户不存在安装成本,打开即用。
另外,诸如 Electron、NW.js 这样的框架,可以让开发者直接使用 WebView + Node.js 模块开发物联网桌面应用。它可以加速 UI 界面的开发,并轻松地美化 UI 界面。
硬件层
在硬件层上,就当前而言,Arduino 是最合适的原型开发硬件,除此还有自带 Wi-Fi 的 ESP8266 开发板。尽管使用 JavaScript 的开发板数量较少,也没有 Arduino 这样的成熟生态,但是未来可期。在嵌入式领域,使用 JavaScript 编写的代码,具有移植性强、事件驱动、天生支持异步等特点。
令人遗憾的是,为了保持上面提到的那些 JavaScript 特性,当前的 JavaScript 开发板都需要处理性能比较高的处理器,这也导致了此类开发板在生产上存在较高的成本。不过,好在多数使用 JavaScript 作为开发语言的设备,都具有网络功能连接到互联网,直接作为物联网设备使用。
就目前而言,这一类的设备有 Tessel、Espruino、Ruff 等等,它们的处理器性能都相当不错,价格也相对较高一些。但是,它们可以直接使用 JavaScript,能为软件开发工程师屏蔽底层相关细节,及事件驱动、异步特性,带来更好的开发体验。
幸运的是,Samsung 公司推出的开源物网框架 IoT.js,只需要 64KB RAM、200 KB ROM。在未来,或许它能解决一些制造成本上的问题。
协调层
当我们的硬件层不能直接联网时,协调层就可以完成这样的功能。作为一个协调层的设备,它应该能与一定数量的微控制器连接,接收它们的数据,并上传到服务端;又能与服务端通讯,获取一些控制指令,并将这些指令准时地发送给不同的控制器。所以,它需要有更好的处理能力、更多的 RAM、ROM 等等。因此,在这一层级使用 JavaScript 便不存在成本问题。我们只需要使用和服务端、应用层相似的知识,就可以快速地连接设备到网络中心。还能直接在本地的 Linux 机器上编写代码,并无缝地运行在设备上。
图8 物联网协调层
这一类应用,依赖于 Node.js 引擎来实现快速开发。它可以运行在带有嵌入式系统的开发板上,如流行的 Raspberry Pi、OpenWRT 路由器等。
我们只需要一个运行嵌入式 Linux 系统的开发板,就可以完成这样的工作。与此同时,主流的 ARM 开发板都提供相应的 Linux 移植,因此在这个层级,我们也只需要关注于业务的实现。
小结
如上所述,物联网应用的架构与 Web 应用的架构区别并不是太大,只是在这上面做一系列的演进。除了上面提到的一系列快速实践框架,当前在 Web 开发中流行的一些开发思想,势必也会引导到物联网系统中:
微服务化;
DevOps;
容器化。
物联网会吸引互联网的优秀开发思想,并演进出更优秀的架构。
使用 JavaScript 和 MQTT 开发物联网应用
文/刘彦玮
如果说 Java 和 C# 哪个是最好的开发语言,无疑会挑起程序员之间的相互怒怼,那如果说 JavaScript 是动态性最好的语言,相信大家都不会有太大的争议。随着越来越多的硬件平台和开发板开始支持J avaScript,JavaScript 在硬件端以及物联网领域有了新的机会。
IoT 应用开发的数据链路
图1是一个智能家居物联平台的数据链路。
图1 智能家居物联平台的数据链路
一般来说,可以把 IoT 应用分为如图所示的四层。
client 层:指的是 IoT 设备,可以是冰箱、空调,也可以是一些温湿度传感器。
gateway 层:大多数场景中 gateway 是家里的 WiFi 路由器,也有小部分是基于 Zigbee 或蓝牙的网关设备。智能生活场景中的 gateway 数量相对于工业领域要少很多,在工业领域存在大量的边缘计算放在 gateway 层进行处理(雾计算)。
cloud 云层:这里是集中处理业务的地方。
应用层:这一层是直接与用户打交道的地方,可以是通过电脑的 Web 浏览器、手机 App,也可以是有屏幕的智能设备的显示器。随着语音技术的发展,无屏设备也可以通过语音交互,作为一个应用存在于物联网的交互层。
物联设备(下文统称为 client),可以是单个设备或多个设备组成的应用场景。比如冰箱把运行的功耗数据、库存数据、温度数据采集,通过 gateway 发送到 cloud 层,cloud 层收集数据后进行异常判断,做智能模式推荐等业务处理后到 application 层进行展现和交互。用户可以通过冰箱的设备数据进行模式选择,还可以做一些与设备无关的增值服务,比如听音乐、买菜等,这就是一个智能冰箱的数据链路。还有些 client 是成组智能场景的,比如温湿度传感器将数据上传到 cloud,经过处理和加工,动态控制家中空调的温度,调节空气净化器的运行模式等。这么描述好像没有体现出 cloud 层的作用,那如果运行模式是用户预先配置好的呢?如“当温度超过25度,请帮我打开空调”,这些业务都可以通过 cloud 层进行处理。
client 层的连接方式有 WiFi、Bluetooth、Zigbee,而 MQTT 是为了让物联网设备更加互联互通而出现的应用层数据协议。
MQTT+JavaScript
MQTT 是一个长连接的通讯应用层协议,最大的特点是数据精简、消息可靠、Publish-Subscribe 模式灵活易用。MQTT 已经成为 IoT 传输的标准协议,应用非常广泛。
图2中 Client 指的是物联网设备。Client 通过对 Topic 的订阅和发布数据管理应用中的数据流动,而 Broker 是 MQTT 应用中用于管理 Topic 的角色。Server 是物联网应用中的服务端,用于处理业务逻辑。
MQTT 被广泛使用的一个重要的原因是 MQTT 的生态非常完善,同时也支持 JavaScript。因此图2所示的所有链路和模块,都可以通过 JavaScript 实现。
图2 MQTT 的数据链路图
JavaScript 在 MQTT 架构中常用的框架
mosca(https://github.com/mcollina/mosca)
mosca 是一个用 JavaScript 实现的 MQTT Broker。不仅如此,mosca 还增加了对数据库,如 Redis、MongoDB 的支持,用来实现消息数据的存储。MQTT.js(https://github.com/mqttjs/MQTT.js)MQTT.js 是官网推荐的 JavaScript 实现的 Client 端。
KOA 和 Express
这两者都是非常主流的 Node 版本的 Server,简单易用。
图3 JavaScript 在 MQTT 架构中常用的框架
实战物联网应用
这节我们运用之前介绍的框架,自己动手完成一个简单的物联网应用。应用场景如图4所示,温度传感器用于接收温度,并把文档通过 MQTT 发送到 Server 端,在 Server 端进行业务处理,根据温度计算出穿衣提示,通过 MQTT 把数据发送到特定的 Topic,App 订阅 Topic 获取数据后进行展现。
图4 “穿衣提示”业务场景框架
Broker 端的实现
Broker 端使用 mosca,参考网页https://github.com/mcollina/mosca。
安装 mosca。
nmp install mosca --save
启动 mosca。这里需要注意,如果本地没有配置 MongoDB,则需要把 ascoltatore 中的内容全部注释掉。
var mosca = require('mosca');var ascoltatore = { //using ascoltatore // type: 'mongo', // url: 'mongodb://localhost:27017/mqtt', // pubsubCollection: 'ascoltatori', // mongo: {}};var settings = { port: 1883, backend: ascoltatore};var server = new mosca.Server(settings);server.on('clientConnected', function(client) { console.log('client connected', client.id);});// fired when a message is receivedserver.on('published', function(packet, client) { console.log('Published', packet.payload); //{"clientId":"mqttjs_02fea7b4","topic":"/tips"} // console.log('>>>packet', packet); //{"clientId":"mqttjs_02fea7b4","topic":"/tips"}});server.on('ready', setup);// fired when the mqtt server is readyfunction setup() { console.log('Mosca server is up and running');}
代码完成后,启动文件,本地的一个 Broker 就跑在 localhost 的1883端口上了。
Client 端的温度传感器实现
Client 使用 MQTT.js 实现,参考网页https://github.com/mqttjs/MQTT.js
安装
npm install mqtt --save
启动
var mqtt = require('mqtt');var client = mqtt.connect('mqtt://localhost:1883');client.on('connect', function () { console.log('>>> connected') // client.subscribe('/tips') setInterval( ()=>{client.publish('/temperature', '30');}, 3000 );})client.on('message', function (topic, message) { // message is Buffer console.log(message.toString())})// client.end();
执行 Node index 后 Client 就启动了,可以看到在 MQTT.connect 方法中连接了上一节中启动的 Broker 地址,连接成功后,Client 会输出日志,“>>> connected”,Broker 的控制台也会输出 Client 的连接信息。
这里模拟了温度传感器,定时3秒向 /temperature 的 Topic 中发送温度数据。
本节的温度器可以在电脑中使用 Node 方式运行,也可以运行在支持 JavaScript 的开发板中,如 RUFF、NodeMCU、Raspberry Pi,并且可以使用真实的传感器。
Server 的实现
Server 使用 MQTT.js 订阅 Client 发送到 /temperature Topic 的数据进行处理,把处理后的数据转译成 JSON 发送到另一业务主题 /tips 中。
实现代码如下:
'use strict'const mqtt = require('mqtt');var client = mqtt.connect('mqtt://localhost:1883');client.on('connect', function () { console.log('>>> connected'); client.subscribe('/temperature');})client.on('message', function (topic, message) { var temperature = parseInt(message.toString()); var data = {temperature}; if (temperature >= 60) { data.tips = "热... 500服务器故障"; } else if (temperature >= 50) { data.tips = "今天天气非常热,建议不要穿衣服了"; } else if (temperature >= 40) { data.tips = "今天天气十分的热,建议穿短袖T恤+短裤"; } else if (temperature >= 30) { data.tips = "今天天气有点的热,建议穿短袖T恤"; } else if (temperature >= 0) { data.tips = "今天天气正好,可以穿上一件薄衣服"; } else if (temperature >= -10) { data.tips = "今天天气十分寒冷,棉袄可以穿上一件"; } else { data.tips = "今天天气十分十分寒冷,棉袄可以穿上二件"; } client.publish('/tips', JSON.stringify(data)); // if (temperature+1) {} // message is Buffer console.log(JSON.stringify(data));})
App 的实现
Demo 的 App 使用 KOA 启动一个 Web,在 Web 中展现当前温度对应的穿衣提示,通过订阅 tips 获取数据。
安装 koa
$ npm install koa
实现代码
'use strict'const Koa = require('koa');const mqtt = require('mqtt');const app = new Koa();var msg = {temperature:"-",tips:""};// responseapp.use(ctx => { ctx.body = "当前温度:" + msg.temperature + "度" + "\n" + '穿衣提示:'+msg.tips + "\n" ;});app.listen(3000);//mqttvar client = mqtt.connect('mqtt://localhost:1883');client.on('connect', function () { console.log('>>> connected'); client.subscribe('/tips');})client.on('message', function (topic, message) { var data = JSON.parse(message.toString()); console.log(message.toString()); console.log(data.tips); msg = data; // if (temperature+1) {} // message is Buffer // let str = message.toString(); // let data = JSON.parse(message); // console.log(data.tips); // msg = message.toString();})
Demo 小节
本章给出了一个简单的物联网业务的业务场景和实现逻辑,其中 Client 也可以运行在电脑上进行 Demo 查看,或是跑在真实物联设备或开发版上。如图5,笔者使用 RUFF 开发板实现了一次。
完整 Demo 代码已经分享在 github 中,大家可以输入 URL 下载。
https://github.com/coolnameismy/javascript-mqtt-demo-wearingTip
图5 Demo 硬件演示
总结
本文和大家交流了物联网应用的一般数据链路、MQTT 协议的架构,并基于 MQTT 实现了一个简单的物联网应用。现在正是前端工程师的大好机会,越来越多的嵌入式设备都开始支持 JavaScript,原因是现在有很多 JavaScript 引擎可以把 JavaScript 转换成各种平台的底层代码,比较有名的有 Jerryscript、Duktape 等。随着越来越多的 JavaScript 工程师进入嵌入式开发的领域,嵌入式应用开发也会出现前后端分离的情况(应用开发或是驱动开发),类似于 Web 开发的前后端分离。前端关注在应用、创意、数据链路、用户体现上,而后端则关心 GPIO、I2C 的底层数据接口和驱动,平台兼容性等方向。
游历 JavaScript IoT 应用开发平台
使用 Python 进行物联网端到端原型开发
管中窥豹:一线工程师看 MQTT
物联网安全与实战
未来物联网全栈开发 JavaScript or Python?
IoT 通讯技术选型及模型设计的思考
微软百度阿里三大物联网云平台探析
如何基于 Android Things 构建一个智能家居系统?
浅析物联网应用层协议 CoAP
蓝牙 Mesh 技术初探
阅读全文: http://gitbook.cn/gitchat/geekbook/5a62a6755418822a9fb0c246