物联网(Internet of Things,简称IoT)时代的脚步声已经越来越响亮,每个程序员都希望跟上时代的步伐,不为时代浪潮所淘汰。面对IoT这个纷争初起的领域,程序员们该何去何从?本文将带领诸位进行一次IoT应用开发平台的游历之旅,帮助大家了解该领域当今的发展状态,尤其是基于JavaScript的IoT应用开发平台,为各位搭车IoT奠定一些基础。
开启行程之前,我们先明确讨论范围,在行业里,谈到IoT开发平台,有人说的是云,如各大云厂商;有人说的是硬件端,如各家硬件厂商;在这里我们将讨论是,硬件端的开发平台,对于大多数软件开发人员而言,这是一个更加陌生的领域。
IoT应用开发平台简介
在IoT应用开发领域中,大家熟知的开发平台主要有如下几类:
- 嵌入式操作系统,包括VxWorks、FreeRTOS、LiteOS等;
- 极客硬件平台,包括树莓派、Arduino等;
- JavaScript IoT应用开发平台,包括Ruff、Tessel、JerryScript、Johnny-Five等。
嵌入式操作系统,从功能的角度上来说,能够满足目前的绝大多数需求。但是:
- 其入门门槛极高,开发者想要成为优秀的嵌入式开发工程师,需要学习大量软硬件知识。相较于软件行业,嵌入式领域的人才数量受到了限制。
- 嵌入式领域在开发方法上已经大幅度落后于整个行业的发展。敏捷软件开发方法以及精益创业的理念,受到工具所限,在嵌入式领域极少得到应用,所以该领域在工程方法上发展缓慢。
- 这些操作系统的编程概念通常属于专用领域,所以知识很难在行业中共享,开发者在行业中流动也相对困难,造成的结果是,嵌入式领域对于现代软件开发理念的理解也整体上落后于软件行业。
极客硬件平台,其初衷是降低开发门槛,让更多开发者得以进入到硬件开发领域中。但是:
- 它只是在操作方面的入门难度上在努力,而开发真正困难的部分在编程概念。对于大多数软件开发者而言,难点在于硬件中的编程概念。各种各样的接口及参数,这是软件开发者难于理解和掌握的。
- 更关键的因素是,这些平台只解决了原型开发的问题。开发者即便能够通过它实现了一个产品原型,也很难将它用到真正的产品中。应用到产品中,往往要重新设计硬件,这些平台的优势就荡然无存了。
二者最本质的复杂度在于其编程模型,对于软件开发者来说,GPIO、I2C之类硬件接口完全是另一种语言,除了要了解接口的编程方法,还要针对每个硬件,阅读其数据手册,了解参数细节。
目前为止,诸位会想,IoT行业对软件工程师简直犹如另一个世界,一点都不友好。是的,很多人都是这么想的,于是,有人想用更高级的语言改变这个世界,这其中最为活跃的便是JavaScript社区。
JavaScript IoT应用开发平台
JavaScript IoT应用开发平台,其建设初衷是让开发者能够用JavaScript开发IoT应用,一方面可以更好地构建抽象,另一方面,可以将比较现代的开发方式引入到硬件研发中。JavaScript IoT应用开发平台目前主要分为几大类:
- 在硬件上运行JavaScript,如JerryScript、Espruino等;
- 提供硬件抽象能力,比如Tessel、Johnny-Five、Cylon.js等;
- 面向生产的能力,如Ruff。
在硬件上运行JavaScript的平台
该类平台主要解决的问题是让硬件平台具有运行JavaScript程序的能力,主要是在资源受限的硬件上,比如MCU(Microcontroller Unit,微控制器,又称单片机),你可以把MCU理解成内存很小的芯片,时至今日,谈及单片机,内存通常以K为单位。
Espruino
网站:https://www.espruino.com
Espruino是将JavaScript与硬件开发连接起来的先驱,其设计目标就是能够在单片机上运行 JavaScript。除了提供引擎之外,Espruino还提供了一些访问底层设备的程序库,下面是一段代码示例:
function toggle() {
on = !on;
digitalWrite(LED1, on);
digitalWrite(LED2, !on);
} |
其中,digitalWrite是Espruino提供的方法。由于出现的比较早,其程序与今天行业里的主流编程风格有一些差异,偏向于传统的C代码风格。
从架构上说,Espruino做得也差强人意,它将解释器、程序库、底层系统混在了一起,移植起来有一定难度。
JerryScript
网站:http://jerryscript.net
JerryScript是三星打造的一款JavaScript引擎,它可以运行在64K的MCU上,其相对比较年轻,对于JavaScript标准支持得比较好,能够完整支持ECMAScript 5.1。JerryScript只是一个JavaScript引擎,而真正提供设备访问能力是IoT.js。
IoT.js
网站:http://iotjs.net/
IoT.js的本意是打造一个类似于Node.js的运行时,所以,它提供Buffer、net、timer等一些标准模块。当然,最主要的是它提供的设备访问能力,下面是一段示例代码:
var i2c = require('i2c');
var wire = new i2c(0x23, {device: '/dev/i2c-1'});
wire.scan(function(err, data) {
...
}); |
这段代码是一段访问I2C接口的代码,如果你不了解硬件接口,这段代码理解起来还是有些难度的。但不难看出,其代码风格已经接近于今天行业里的主流编程风格。
仅仅提供在硬件上运行的JavaScript能力是不够的,严格来说,其暴露的依旧是底层的编程接口,面临与传统硬件开发所面对的问题一致,即编程模型无法让软件开发者很好的理解。所以,提供硬件抽象,成为了IoT应用开发平台另一个重要的探索方向。
提供硬件抽象的JavaScript IoT应用开发平台
该类平台提供软件抽象能力,让更多的软件开发人员使用他们熟悉的语言进入到在IoT领域。有了硬件抽象,软件开发者面对不再是GPIO、I2C之类的底层接口,而变成了具有开关功能的LED、能够监测按键按下松开的按钮。这是一个极大的进步,硬件世界的大门对软件开发人员打开了。
Tessel
网站:https://tessel.io
Tessel是一个稳定的IoT和机器人开发平台,利用Node.js所有的程序库创建有用的设备。下面是一段示例代码,定期将声级上报到一个地方。
var tessel = require('tessel');
var ambientlib = require('ambient-attx4');
var WebSocket = require('ws');
var ambient = ambientlib.use(tessel.port['A']);
var ws = new WebSocket('ws://awesome-app.com/ambient');
ws.on('open', function () {
setInterval(function () {
ambient.getSoundLevel(function(err, sdata) {
if (err) throw err;
sdata.pipe(ws);
})
}, 500);
}); |
Tessel自身除了出品软件,也提供硬件开发板,不过,Tessel程序也只能运行于Tessel开发板上。
Johnny-Five
网站:http://johnny-five.io
Johnny-Five是一个JavaScript机器人和IoT平台,由Bocoup公司于2012年发布。下面这段示例代码,让LED定期闪烁:
var five = require("johnny-five");
var board = new five.Board();
board.on("ready", function() {
var led = new five.Led(13);
led.blink(500);
}); |
Johnny-Five不生产开发板,它的程序可以运行于多款开发板上,其缺省支持的是Ardunio,如果需要其他开发板,可以在Board初始化的时候指定,比如下面这段代码就使用了Edison开发板。
var Edison = require("edison-io");
var board = new five.Board({
io: new Edison()
}); |
Cylon.js
网站:https://cylonjs.com
Cylon.js是一个为机器人、物理计算以及IoT而设计的JavaScript框架,其目的是让控制机器人和设备变得容易。下面这段示例代码让LED每秒闪烁一次:
var Cylon = require("cylon");
Cylon.robot({
connections: {
arduino: { adaptor: 'firmata', port: '/dev/ttyACM0' }
},
devices: {
led: { driver: 'led', pin: 13 }
},
work: function(my) {
every((1).second(), function() {
my.led.toggle();
});
}
}).start(); |
与Johnny-Five类似,Cylon.js也是依赖于别人的开发板。
Tessel、Johnny-Five、Cylon.js三者有着类似的努力方向,即提供软件抽象,这是很好的做法,也让许多软件开发人员看到了IoT的曙光。但是,其基础上的一些问题,决定了他们只能是作为开发者的玩具:
- 在硬件上运行的能力,这几个平台实际上都是在电脑上运行,然后发送命令控制硬件,也就是用它们开发的应用,需要一个控制端。
- 更重要的的是,其运行JavaScript的基础是Node.js,这是一种用于电脑上的JavaScript运行时,它无法运行于一个资源受限的硬件上,而真实环境中,资源受限硬件才是行业主流。这意味着,这些框架即便未来希望做改造,难度也是很大的。
- 这些平台虽然在代码级别提供了抽象,但仍然有许多硬件配置的内容,比如pin、port之类,对于软件开发人员而言,理解起来还是有门槛的。
由此可见,这些平台的现状只是解决了编程接口的抽象,并没有真正的实现软硬件的隔离。所以,有平台开始了进一步的探索,提供面向生产的能力。
面向生产的JavaScript IoT应用开发平台
该类平台可以理解成将前面两种类型的能力综合在一起,并进一步改进:既能在资源受限的硬件上运行,又提供在硬件抽象,将硬件相关内容进一步抽象,将软硬件进一步分离。
Ruff
网站:https://ruff.io
Ruff是一个支持JavaScript应用开发的物联网操作系统,其目标是打造一个IoT版本的Android。下面是一段Ruff示例代码,按下按键,点亮LED,松开之后,灯熄灭。
'use strict';
$.ready(function(error) {
if (error) {
console.log(error);
return;
}
$('#button').on('push', function () {
$('#led-r').turnOn();
});
$('#button').on('release', function () {
$('#led-r').turnOff();
});
});
$.end(function() {
$('#led-r').turnOff();
}); |
这段代码已经没有任何与硬件配置相关的代码,完全是应用的逻辑。即只要提供不同的硬件配置,代码就可以运行在不同的硬件上。
事实上,Ruff也确实做到了这点,它既可以支持像树莓派这样能够运行Linux系统的硬件上,也支持像TM4C1924这样的MCU。做到跨硬件,需要从架构设计上有很好的支持,这也是Ruff的一大优势。
从Ruff提供的特性上看,其企图不止于将引入抽象,更试图将现代软件开发理念带入到IoT应用研发之中:
- 彻底地分离硬件、系统与应用,使三者可以用不同的节奏发布,让IoT应用的迭代开发成为可能;
- 设计测试框架,让开发者可以在开发机上测试应用逻辑,无需部署到真实硬件,大幅度节省了开发调试的时间,从而降低了开发成本;
- 采用软件包的方式管理各种模块,尤其是驱动,使得模块得以在共享,知识得以流动;
- 采用命令行的方式进行对相关内容进行管理,比如,板卡、外设驱动、系统升级等等,便于与第三方工具集成。
Ruff正试图建立一个全新的IoT应用开发平台,所以,它支持的硬件数量相对前期发展时间比较长的平台来说,还是相当有限的。但其架构展现的扩展性是足够的,对于开发者而言入门门槛也足够低,如果有更多开发者进入,其未来发展是值得期待的。
衡量IoT应用开发平台
从前面一系列介绍,我们已经了解了许多IoT应用开发平台,尤其是基于JavaScript的IoT应用开发平台,作为开发者,我们该如何选择呢?我们不妨梳理出一个IoT应用平台的衡量标准,然后,根据实际场景自行选择。
采用JavaScript语言
传统嵌入式开发采用C/C++作为主流的程序设计语言,对于现代软件开发而言,这种做法存在一些问题:
- 缺少自动化内存管理能力,普通程序员经常会犯一些低级错误,造成程序崩溃;
- 缺少标准库,开发者浪费了大量的时间,在构建基础设施;
- 缺少可移植标准,每次面对不同的硬件,都需要花费大量时间,让代码在新平台上运行起来;
- 缺少包管理能力,不同的程序员会反复构建类似的代码,造成行业的浪费;
- 对于测试缺少内建的支持,测试的编译运行会随着代码规模而不断增长,没有小步开发的基础。
JavaScript作为行业里唯一一门全栈式开发语言,拥有着广泛的开发人员基础,随着Node.js的兴起,配套的基础设施也得到长足的进步,完全可以称之为一门合格的现代开发语言:
- 支持GC,开发者无需顾忌内存;
- 支持面向对象和函数式编程等多种现代编程范式,开发者可以根据需要自行选择;
- 程序可移植,底层差异由运行时屏蔽;
- NPM软件仓库,几十万个软件模块,开发者按需取用,无需重复造轮子;
- 有多种测试框架,开发者可以很容易在开发环节中进行测试。
作为其他高级语言的开发者,你或许会有疑问,其他语言这些特性似乎也可以支持。还有如下几点让JavaScript脱颖而出:
- 运行时,如Python、Java之类的语言,很少有能对MCU进行支持的运行时,这使得它们顶多能做到原型级别开发,而无法深入。
- 流行程度,类似于Lua这种本身运行时很小的语言在嵌入式环境中也有应用,也确实有一些项目做到了,比如NodeMCU,但Lua目前属小众语言,其前景取决于行业发展状况。
设计硬件抽象
传统的嵌入式开发平台存在极高的门槛,一个非常重要的原因在于,其系统及应用是一体的,任何一个开发者都需要学习很多的知识,才能成为一个合格的嵌入式开发者。
引入硬件抽象,将实现系统与应用的分离,应用开发者会像使用普通的程序库一样操作硬件,而无需关注底层实现细节,这样可以更好地把注意力放在应用上。
硬件抽象也分为不同的级别:
- 编程接口,让开发者使用软件抽象,屏蔽底层硬件接口,这是很多提供硬件抽象的平台几乎都能做到的。
- 硬件配置,将硬件配置进行隔离,让开发者不必关注配置细节,面对做不到这点的平台,开发者还是要了解很多细节。
总的来说,硬件抽象也大幅度降低了门槛,软件开发者可以从应用的角度理解IoT应用,无需学习底层细节,从而让更多开发者得以进入到IoT研发领域中。从人数上说,软件开发者的数量远大于专攻硬件研发的开发者。降低门槛,将软件开发者引入到一个全新领域所带来的变化,我们已经在移动开发领域看过了一遍。有了好的IoT应用开发平台,相信同样的戏码会在IoT领域重演。
面向生产
如果只是构建一个原型,其难度与构建一个真实的应用不可同日而语。软件开发者理解这一点并不困难。在IoT领域,问题是一样的。真实的IoT应用,会面对功耗、价格、性能等诸多问题,这也是在今天,计算资源极大丰富的情况下,在IoT领域依然对资源斤斤计较的原因,资源受限的硬件才会大行其道。无论如何,能够运行在资源受限的硬件上,是成为一个真正的IoT应用开发平台的前提。
在传统的嵌入式开发中,应用与硬件是紧密耦合在一起的,如果能够实现应用与硬件配置相分离,将带来极大的改变:
- 应用开发者无需关注硬件如何配置,可以将更多的将注意力放在应用逻辑本身;
- 硬件具体的配置方式可以在具体的部署时实施。
这样做还会带来一些额外的好处:
- 应用与硬件配置分离,让应用的移植成为可能。应用在开发时可以不知道具体实施的硬件,只要在具体交付时,将应用部署在硬件上即可;
- 二者的分离实现了研发与生产相分离,双方可以各自独立发展,由此可以实现更好地分工;
- 分离让研发和生产可以采用不同的硬件,这会对研发流程带来一些改变,在研发期采用既有硬件进行测试,在完成需求验证之后,再根据情况生产实际的硬件;
- 硬件、系统与应用将成为三个独立的概念,可以用不同的节奏发布,迭代开发成为可能。
总结
现如今,IoT行业主流的开发方式依旧是采用传统的C/C++进行嵌入式开发。但从行业发展的状况不难看出,这种方式已经阻碍了更多人才的进入,更进一步阻碍IoT的普及,工具的升级已经迫在眉睫。新近的JavaScript IoT应用开发平台已经逐渐展现出其未来的发展前景,但是,所有的JavaScript IoT应用开发平台都面临着一个问题:缺乏成熟的行业解决方案。从时间上来说,它们都处于早期,被行业选择和接收需要一个过程。但IoT要发展,工具要升级,JavaScript IoT应用平台是目前最有力的竞争者。
基于此,我们共同游历了当今的IoT应用开发平台,尤其是基于JavaScript的IoT应用开发平台。并了解了IoT应用平台的衡量标准,希望这些内容在大家进入IoT领域时,会有所帮助。
让我们共同迎接这曙光乍现的IoT时代吧! |