物联网(Internet of Things,简称IoT)时代的脚步声已经越来越响亮,每个程序员都希望跟上时代的步伐,不为时代浪潮所淘汰。面对IoT这个纷争初起的领域,程序员们该何去何从?本文将带领诸位进行一次IoT应用开发平台的游历之旅,帮助大家了解该领域当今的发展状态,尤其是基于JavaScript的IoT应用开发平台,为各位搭车IoT奠定一些基础。
开启行程之前,我们先明确讨论范围,在行业里,谈到IoT开发平台,有人说的是云,如各大云厂商;有人说的是硬件端,如各家硬件厂商;在这里我们将讨论是,硬件端的开发平台,对于大多数软件开发人员而言,这是一个更加陌生的领域。
在IoT应用开发领域中,大家熟知的开发平台主要有如下几类:
嵌入式操作系统,从功能的角度上来说,能够满足目前的绝大多数需求。但是:
极客硬件平台,其初衷是降低开发门槛,让更多开发者得以进入到硬件开发领域中。但是:
二者最本质的复杂度在于其编程模型,对于软件开发者来说,GPIO、I2C之类硬件接口完全是另一种语言,除了要了解接口的编程方法,还要针对每个硬件,阅读其数据手册,了解参数细节。
目前为止,诸位会想,IoT行业对软件工程师简直犹如另一个世界,一点都不友好。是的,很多人都是这么想的,于是,有人想用更高级的语言改变这个世界,这其中最为活跃的便是JavaScript社区。
JavaScript IoT应用开发平台,其建设初衷是让开发者能够用JavaScript开发IoT应用,一方面可以更好地构建抽象,另一方面,可以将比较现代的开发方式引入到硬件研发中。JavaScript IoT应用开发平台目前主要分为几大类:
该类平台主要解决的问题是让硬件平台具有运行JavaScript程序的能力,主要是在资源受限的硬件上,比如MCU(Microcontroller Unit,微控制器,又称单片机),你可以把MCU理解成内存很小的芯片,时至今日,谈及单片机,内存通常以K为单位。
Espruino
Espruino是将JavaScript与硬件开发连接起来的先驱,其设计目标就是能够在单片机上运行 JavaScript。除了提供引擎之外,Espruino还提供了一些访问底层设备的程序库,下面是一段代码示例:
function toggle() { on = !on; digitalWrite(LED1, on); digitalWrite(LED2, !on); }
其中,digitalWrite是Espruino提供的方法。由于出现的比较早,其程序与今天行业里的主流编程风格有一些差异,偏向于传统的C代码风格。
从架构上说,Espruino做得也差强人意,它将解释器、程序库、底层系统混在了一起,移植起来有一定难度。
JerryScript
JerryScript是三星打造的一款JavaScript引擎,它可以运行在64K的MCU上,其相对比较年轻,对于JavaScript标准支持得比较好,能够完整支持ECMAScript 5.1。JerryScript只是一个JavaScript引擎,而真正提供设备访问能力是IoT.js。
IoT.js
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应用开发平台另一个重要的探索方向。
该类平台提供软件抽象能力,让更多的软件开发人员使用他们熟悉的语言进入到在IoT领域。有了硬件抽象,软件开发者面对不再是GPIO、I2C之类的底层接口,而变成了具有开关功能的LED、能够监测按键按下松开的按钮。这是一个极大的进步,硬件世界的大门对软件开发人员打开了。
Tessel
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
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开发板。
Cylon.js
Cylon.js是一个为机器人、物理计算以及IoT而设计的JavaScript框架,其目的是让控制机器人和设备变得容易。下面这段示例代码让LED每秒闪烁一次:
与Johnny-Five类似,Cylon.js也是依赖于别人的开发板。
Tessel、Johnny-Five、Cylon.js三者有着类似的努力方向,即提供软件抽象,这是很好的做法,也让许多软件开发人员看到了IoT的曙光。但是,其基础上的一些问题,决定了他们只能是作为开发者的玩具:
由此可见,这些平台的现状只是解决了编程接口的抽象,并没有真正的实现软硬件的隔离。所以,有平台开始了进一步的探索,提供面向生产的能力。
该类平台可以理解成将前面两种类型的能力综合在一起,并进一步改进:既能在资源受限的硬件上运行,又提供在硬件抽象,将硬件相关内容进一步抽象,将软硬件进一步分离。
Ruff
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应用研发之中:
Ruff正试图建立一个全新的IoT应用开发平台,所以,它支持的硬件数量相对前期发展时间比较长的平台来说,还是相当有限的。但其架构展现的扩展性是足够的,对于开发者而言入门门槛也足够低,如果有更多开发者进入,其未来发展是值得期待的。
从前面一系列介绍,我们已经了解了许多IoT应用开发平台,尤其是基于JavaScript的IoT应用开发平台,作为开发者,我们该如何选择呢?我们不妨梳理出一个IoT应用平台的衡量标准,然后,根据实际场景自行选择。
采用JavaScript语言
传统嵌入式开发采用C/C++作为主流的程序设计语言,对于现代软件开发而言,这种做法存在一些问题:
JavaScript作为行业里唯一一门全栈式开发语言,拥有着广泛的开发人员基础,随着Node.js的兴起,配套的基础设施也得到长足的进步,完全可以称之为一门合格的现代开发语言: