使用 JavaScript 进行硬件黑客攻击
已发表: 2022-03-10物联网(IoT) 使互联网能够超越浏览器。 这些“东西”由电子网络设备组成,能够通过传感器与物理世界交互,传感器将捕获的数据反馈回生态系统。
目前,这些设备大多是产品,设计时考虑到特定目的,一个典型的例子是追踪活动的健身手环。 它将收集到的信息报告给应用程序,然后应用程序能够分析数据并提供建议和动力以进一步推动用户。
关于 SmashingMag 的进一步阅读:
- 选择正确的原型设计工具
- 如何原型物联网体验:构建硬件
- 原型物联网体验:配置软件
- 使用 TAP 和 Adobe Fireworks 进行 iOS 原型设计
在构建物联网设备时,任务通常分为两个角色:硬件工程师创建物理设备,开发人员创建生态系统。 然而,这并不总是必要的。 就 JavaScript 而言,它的同构特性允许一种语言在多个平台(包括硬件)上使用。
这是乔治,会说话的植物,物联网的一个(相当暴躁的)补充。 他的传感器收集周围环境的数据,包括土壤的水分含量、环境温度和光照强度。 凭借他的 8 × 8 LED 脸,他能够将他的不满形象化,并使用 HTML5 的 Web Speech API 讽刺地回答您的平凡问题。 George 是一个很好的例子,说明了如何使用与硬件相结合的 Web 技术来提供新的和引人入胜的体验。
本文介绍了如何开始使用 JavaScript 为您自己的 IoT 设备构建的基础知识。
入门
传统上,只有电气工程师才会尝试构建硬件原型和联网设备。 随着 Arduino UNO、Particle(以前的 Spark Core)和 Raspberry Pi 等开发板的出现,这种情况发生了变化。
开发板模仿计算机上的主板。 它们具有输入和输出插座,例如 USB 和电源,以及允许您添加外部组件的插针板。 微控制器芯片充当处理器,运行应用程序代码并与输入和输出通信。 该芯片相对较慢,专门设计用于执行简单的任务,例如读取传感器数据。 但是,它还具有切换能力,可以改变灯、电机和更多组件的电源。

创客运动在过去几年中越来越受欢迎,构建物联网设备已成为一项大生意。 这扩大了开发板的市场,现在提供的范围很广,每个都有自己的特点。 竞争导致许多人专注于独特的卖点,例如无线通信(使用 Wi-Fi 和蓝牙芯片)、尺寸和电池寿命。 在构建您自己的设备时,您需要考虑您需要哪些物理属性。 同样,软件也会影响决策,例如您可以在板上运行的编程语言。 彻底研究并选择最适合您需求的电路板。
在此处的示例中,我们使用的是 Arduino UNO。 这种特殊的开发板可能是市场上最受欢迎的,因为它非常易于使用。 如果您刚刚开始,我们建议您购买入门套件,类似于 Arduino 提供的东西。 它将为您选择的开发板提供兼容的组件,并且通常会提供大量文档来帮助您入门。
电力和电路的基础知识
顾名思义,电子电路是圆形的。 电子从电路周围的电源(例如电池)的正极流向同一电源的负极。
了解电路内部发生的物理现象的最简单方法是将其与水箱系统进行比较。 管道中的水就像电线中的电子一样流动。 这些电子形成了为电路组件供电的电流。

正如储存在水箱中的水量会影响水龙头上的压力一样,电源中的电子越多,它的充电量就越多。 这是电压。 电压越高,负极和正极之间存在的电压就越大,从而控制电路周围电子的速度。
就像一定体积的水流过管道一样,电路的电流是指流过导线的电子数量。 这在构建电路时很重要,因为您需要确保每个组件都接收到足够的数据来执行其任务。 电流以安培或安培 (A) 为单位测量,可以为我们提供有关使用的电子数量的信息。 例如,如果电机消耗 100 毫安 (mA),而电池的容量为 1000 毫安/小时 (mAh),那么我们一次充电可以使电机运行 10 小时。

当电路中的组件运行所需的电流比电路中的电流少时,它们可能会接收到过多的功率并中断。 在这种情况下,需要引入阻力以防止这种情况发生。 使用我们的水类比,管道的直径将限制可以流过它的水量,就像电阻限制电子的流动一样。
电阻器是用来降低电流的元件。 它们所施加的电阻大小不同,如电阻器外部的彩色条带所示。 不同的颜色代表不同的数字,将这些带加在一起将显示该特定电阻器的电阻。 (可以使用计算器!)值越高,施加在电路上的电阻就越大,对组件造成损坏的可能性就越小。 使用欧姆定律——电阻等于电压除以电流(或R = V / I
)——您可以计算出电路中所需的精确电阻。
你好世界
在涵盖了基础知识之后,我们可以看一个简单的示例来可视化它们是如何组合在一起的。 我们将进行硬件开发的“Hello World”:让 LED 闪烁。
如前所述,您可以使用多个开发板中的任何一个。 在本例中,我们将使用 Arduino UNO。 我们还将使用运行 Mac OS X 的 Mac,但所有示例也应该在 Windows 上运行。
硬件
你会需要:
- 1 × Arduino UNO
- 1 × 无焊面包板
- 1×标准LED
- 1×220欧姆电阻
- 2 × 跨接电缆

这包括一些尚未提及的组件:
- 跨接电缆用于引导电子流,就像电路中使用任何电线一样。
- LED是发光二极管的简称,本质上是一个小灯泡。 它有一条长腿和一条短腿。 较长的腿表示电路的正流应该进入的位置,较短的腿表示负输出。 如果您弄错了这些方法,LED 将不会亮起。
- 无焊面包板(带孔的白色块)是一种原型制作工具,无需焊接即可创建电路,从而可以轻松更改和纠正电路,以及重复使用组件。 它们有许多不同的形状和大小,但都扮演着相同的角色。
下图显示了电流的流动。 组件可用于将部分链接在一起,如下例中的 LED 和电阻器所做的那样。 在较大的面包板上,外部垂直线通常用于连接正负跨接电缆,以分隔您正在设计的电路。

插入您的组件,如下图所示 - 匹配引脚。 在继续下一节时,这将使事情变得更容易。

要启动电路,请从 Arduino 上的引脚 10 连接一根跳线。 这是 Arduino 开始与电路对话的地方。 您可以使用 Arduino 右侧的任何编号的针脚——只要确保您的代码引用正确的针脚即可。
为确保理想量的电流流过 LED,需要使用电阻器。 与 LED 不同,它以哪种方式插入电路并不重要。
引脚 10 是否允许电流通过(由您的代码控制)将决定 LED 是打开还是关闭。
另一根跳线然后连接到 LED 的负极并返回到地以完成电路。 简单的!
完成后,您的电路应如下图所示。 通过 USB 将其插入计算机。 下一个任务是设置 Arduino 以使用 JavaScript。

在编写任何软件之前,我们需要确保 Arduino 具有正确的固件,以便它可以与 JavaScript 一起使用。 固件本质上为计算机公开了一个 API,以便代码可以通过 USB 端口与电路板交互。
从 Arduino 网站下载并安装集成开发环境 (IDE)。 接下来打开 IDE,确保您的 Arduino 已通过 USB 插入。
在运行任何东西之前,您还需要检查您是否拥有正确的 USB 端口。 转到“工具”→“端口”。 名称可以不同,因此一个好的规则是选择一个端口,在 Mac OS X 上选择名称中包含“tty”和“usb”,在 Windows 上选择名称中包含“COM”的端口。
完成后,您现在可以上传固件。 选择“文件”→“示例”→“Firmata”→“标准 Firmata”。 完成后,选择“文件”→“在 Mac 上上传”(或“草图”→“在 Windows 上上传”)。

现在是时候编写一些 JavaScript 了!
软件
要使用 JavaScript 控制 LED,我们需要使用为 Node.js 构建的名为 Johnny-Five 的库。 基本上,它是由 Bocoup 团队构建的一个库,旨在让网络社区更容易访问构建硬件。 如果您不知道 Node.js 是什么或如何使用它,Elliot Bonneville 在这个网站上有很好的介绍。
因为我们示例的核心使用了 Arduino,所以这个库允许我们的机器通过 USB 端口连接到硬件。
要开始使用,您需要安装 Node.js。 如果不是,您可以从 Node.js 网站下载它。 这还将安装 Node Package Manager (npm),我们将使用它来安装应用程序的所有依赖项。 该示例在 Mac 上运行,使用终端作为命令行工具; 但是,因为 Node.js 是多平台的,所以它可以在任何机器上运行。
本文中的所有代码都可以在 GitHub 上找到。
要安装此项目所需的所有依赖项,您需要创建一个package.json
文件,该文件可以从下面的代码中获取。 这是运行示例所需的库的购物清单。 初始化install
命令后,npm 将出去并获取所有运行所需的所有组件。 此文件必须在您的根文件夹中。
{ "name": "Hardware-Hacking-with-JavaScript", "description": "Smashing Magazine - Hardware Hacking with JavaScript", "version": "0.0.1", "homepage": "https://www.james-miller.co.uk/", "keywords": ["arduino","tutorial","hardware"], "author": { "name":"James Miller & Mate Marschalko" }, "repository": { "type": "git", "url": "git://github.com/jimhunty/Hardware-Hacking-with-JavaScript.git" }, "bugs": "https://github.com/jimhunty/Hardware-Hacking-with-JavaScript/issues", "license": "MIT", "dependencies": { "johnny-five": "^0.9.13" } }
在您的命令行工具中,确保您与package.json
文件位于为此示例创建的同一文件夹中; 然后,运行npm install
。 如果您没有安装这些软件包的权限,请改用sudo npm install
。
现在,您需要创建应用程序代码来运行我们的示例。 我们将此文件命名为blink-led.js
。 评论详细说明了正在发生的事情。
// Johnny-Five is our JavaScript framework for accessing Arduino. var jfive = require("johnny-five"); var board, led; board = new jfive.Board(); // Similar to jQuery, we wait for the board to be ready. board.on("ready", function() { // 10 represents the pin number that the LED is plugged into. led = new jfive.Led(10) // The LED blinks (ie turns on and off) every 1000 milliseconds. led.blink(1000); });
首先,加载库,然后初始化变量。 使用构造函数创建一个新的Board
实例, on ready
函数将使板预热并准备好接收指令。 因为您将连接到 LED 的跨接电缆插入引脚 10,所以需要在led
变量中定义它。 然后使用blink
方法在 1 秒的阶段打开和关闭灯。
现在,您已经拥有了开始这场灯光秀所需的一切——调高音乐! 确保您的 Arduino 已插入并且电路已全部设置好。 在命令行中,运行node blink-led.js
,将文件名替换为您调用的代码。 你现在应该有一个闪烁的灯。
尝试修改代码以使灯闪烁更快或更慢。 每次执行此操作时,您都需要在终端中重新启动代码。 你不妨试试led.pulse()
; 这将使 LED 淡入淡出,而不是仅在没有过渡的情况下切换。
家庭监控
你已经学到了很多东西! 现在您可以将这些知识用于使用并构建一个简单的家庭监控系统,类似于 Nest 和 Hive 等商业产品。
这一次,您将使用温度传感器,从 Node.js 服务器连接到 Arduino。 传感器将读取温度并将其输入浏览器,该浏览器将在一个简单的网页上显示数据。

硬件
你会需要:
- 1 × Arduino UNO
- 1 × 无焊面包板
- 1 × TMP36 温度传感器
- 3 × 跨接电缆
为本示例选择的温度传感器可用于大多数入门套件,并且单独购买非常便宜。

在前面的 LED 闪烁示例中,您设置了计算机上运行的 Node.js 服务器和 Arduino 之间的连接。 此连接还可用于从连接到 Arduino 的传感器读取数据。

以上是完成的电路。 尝试将此引脚与引脚匹配。

处理温度传感器时要小心,因为很容易把腿弄混。 组件的平面是前面,在连接传感器时应该面向您。 由于三条腿中的每一条都有不同的用途,因此错误地接线将意味着您的电路将无法工作。
模拟输入引脚是沿板左侧排列的五个引脚。 Arduino 既有模拟引脚又有数字引脚,既有输入又有输出。 数字意味着只有两种状态——开和关(或电信号和无电信号)——非常适合仅解释两种状态的按钮和其他二进制开关。 另一方面,模拟输入可以表示一系列值,Arduino 上的模拟输入引脚可以测量 0 到 5 伏之间的任何电压(并产生该读数的 10 位值)。 传感器的温度读数将以与空气温度成比例的可变电阻测量值返回。
将传感器中间的信号引脚连接到模拟输入 A0。 将左侧引脚连接到 5V 引脚(正极),将右侧引脚接地(负极)以完成电路。

您的电路现在应该类似于上图。 接下来,您需要创建一个新文件来读取温度传感器。 该文件将以与上一个示例相同的方式启动,加载 Johnny-Five 库,初始化一个新的板实例,然后添加一个on ready
事件侦听器。
var jfive = require("johnny-five"); board = new jfive.Board(); board.on("ready", function() { // We create a new sensor instance and define the sensor type and the pin it's connected to. var tempSensor = new jfive.Thermometer({ controller: "TMP36", pin: "A0" }); // We add an event listener to the sensor and handle the incoming data. tempSensor.on("data", function() { // The data object also has a fahrenheit property, if that's what we are after. console.log(this.celsius + "°C"); }); });
将这段代码保存为temperature.js
,并通过输入node temperature.js
从控制台运行它。
因为代码中使用了console.log
,所以读数会输出到终端进行调试。

服务器和套接字
现在你有一个在 Node.js 中运行的工作温度计。 如果您考虑可用于处理和使用这些数据的所有不同 Node.js 模块,仅这个简单的示例就开启了一系列可能性。 您可以将其保存到 Google 电子表格、发推文或撰写有关它的信息,甚至可以使用 WebSockets 将这些数据实时流式传输到浏览器——这就是您接下来要做的!

要建立与浏览器的连接并传输传感器数据,我们需要启动一个 Node.js HTTP 服务器来提供我们的 HTML 文档,然后打开它们之间的 WebSocket 连接。 使用 Express 库在 Node.js 中启动 Web 服务器相对简单。 首先,从终端安装它:
npm install --save express
安装后,这些代码行将实例化服务器:
// Load libraries and then initialize the server. var app = require('express')(); var http = require('http').Server(app); // When the user requests the root of the page (/), we respond with index.html. app.get('/', function(req, res){ res.sendFile(__dirname + '/index.html'); }); // We listen for connections on port 3000. http.listen(3000, function(){ console.log('listening on *:3000'); });
将此保存为server.js
文件。
在此服务器代码中,前两行加载所需的库并创建一个 HTTP 服务器实例。 接下来,当用户请求根目录 ( /
) 时,简单的路由逻辑会为项目文件夹中的index.html
文件提供服务。 最后,端口3000
监听连接。
要对此进行测试,请在项目文件夹的根目录中创建一个标准index.html
文件。 在命令行中,导航到项目的文件夹并输入node server.js
。 如果您随后在浏览器中键入https://localhost:3000
或您机器的 IP 地址和端口(例如https://190.140.0.00:3000
),您应该会看到标准index.html
页面。 这意味着您的服务器已全部设置完毕。
这绝对比配置 Apache 服务器容易!
在将这段代码与temperature.js
文件合并之前,我们将设置 WebSocket 连接。
WebSocket 使打开浏览器和服务器之间的通信会话成为可能。 使用此 API,您可以发送双向实时消息并接收事件驱动的响应,而无需轮询回复。 Socket.IO 是您将用来建立和处理此连接的 Node.js 模块。 像安装 Express 和 Johnny-5 一样安装 Socket.IO:
npm install --save socket.io
请注意您的package.json
文件现在如何在依赖项下使用 Express 和 Socket.IO 进行更新? 这意味着任何希望在他们的机器上运行您的应用程序的人都可以简单地运行npm install
,并且您加载的所有模块依赖项都将立即安装。 好的! 现在您可以将 WebSocket 功能添加到工作的server.js
代码中。 下面是完整的例子:
var app = require('express')(); var http = require('http').Server(app); // Load the Socket.IO library. var io = require('socket.io')(http); app.get('/', function(req, res){ res.sendfile('index.html'); }); // Establish the WebSocket connection with the browser. io.on('connection', function(socket){ console.log('a user connected'); }); http.listen(3000, function(){ console.log('listening on *:3000'); });
首先,加载 Socket.IO,然后创建一个on connection
事件监听器。 这将在用户加载index.html
文件时触发。
在index.html
页面上,需要初始化 Socket.IO 客户端库以便与服务器通信。 要为此准备 HTML 文件,请在结束body
标记之前添加以下代码:
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script> <script> var socket = io(); </script>
现在应该已经建立了连接,在通过 localhost 链接加载索引页面时,您应该会在命令行中看到“A user has connected”消息。
现在,您可以使用socket.emit()
函数从服务器向浏览器发送消息。 您可以通过替换server.js
中的先前函数来做到这一点:
io.on('connection', function(socket){ console.log('a user connected'); socket.emit('Server message', “Hello from the server!”); });
这是您需要修改index.html
以接收消息的方式:
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script> <script> var socket = io(); socket.on('Server message', function (message) { console.log(message); }); </script>
如果您已正确完成所有操作,您应该会看到“来自服务器的您好!” 浏览器控制台中的消息。 恭喜! 这意味着您已经在 Node.js HTTP 服务器和浏览器之间建立了实时 WebSocket 连接!
这真的非常有用,而且不仅仅适用于这个项目。 WebSocket 连接可用于在多个浏览器之间进行通信,以创建聊天应用程序、多人游戏等等!

现在是时候将处理与 Arduino 通信的temperature.js
文件与负责连接到浏览器的新 WebSocket 服务器代码合并了。
这需要扩展server.js
:
var app = require('express')(); var http = require('http').Server(app); var io = require('socket.io')(http); var jfive = require("johnny-five"); var board = new jfive.Board(); var board, socket, connected = false; app.get('/', function(req, res){ res.sendFile(__dirname + '/index.html'); }); io.on('connection', function(s){ console.log('A user has connected'); // Tracking connection connected = true; // Saving this for the board on ready callback function socket = s; }); board.on("ready", function() { console.log('board has connected'); var tempSensor = new jfive.Thermometer({ controller: "TMP36", pin: "A0" }); tempSensor.on("data", function() { // We send the temperature when the browser is connected. if(connected) socket.emit('Temperature reading', this.celsius); }); }); http.listen(3000, function(){ console.log('listening on *:3000'); });
在这里,您只是从temperature.js
复制了加载 Johnny-Five 并初始化电路板的行,以及整个board on ready
功能。
您还添加了两个新变量:一个用于跟踪 WebSocket 连接,另一个用于存储套接字实例以供其他函数访问——在本例中,用于使用它来发送和接收消息的board on ready
函数。
现在,需要更新index.html
文件以处理来自套接字连接的数据Temperature reading
。 下面的代码需要添加到之前存在Server message
处理程序的脚本元素中的 HTML 文档中。
socket.on('Temperature reading', function (message) { console.log(message); });
界面
最后要做的就是在index.html
中添加几行 HTML 和 CSS,以便以用户友好的方式显示温度读数。 您还将根据温度更新背景颜色,使其在蓝色(冷)和橙色(热)之间变化。 HTML 非常简单:只有一个h1
元素来保存数字。
以下内容需要添加到body
中。
<h1 class="temperature">0C</h1>
大而细的字体应该与数字配合得很好; 试试 Lato,一种来自 Google 字体库的免费字体。 将其加载到文档的head
:
<link href='https://fonts.googleapis.com/css?family=Lato:100' rel='stylesheet' type='text/css'>
在这个例子中,样式是最小的。 唯一棘手的一点是temperature
标签的加载方式。 它使用content
CSS 属性获取类名并将其添加到:before
伪元素中。
body { background-color: hsl(0, 60%, 65%); transition: background-color 1s; } h1 { font-family: 'Lato', sans-serif; font-size: 120px; font-weight: 100; color: white; text-align: center; margin: 60px; } h1:before{ content: attr(class) ":"; font-size: 22px; position: relative; top: -69px; left: 0; text-transform: uppercase; }

这看起来已经很漂亮了!
最后,添加几行 JavaScript 以在接收到 WebSocket 消息时更新值,并更改背景颜色。
<script src="https://cdn.socket.io/socket.io-1.2.0.js"></script> <script> var socket = io(), temperature = document.querySelector(".temperature"); socket.on('Temperature reading', function(message) { // Rounding down the decimal values and adding C temperature.innerHTML = parseInt(message) + "C"; // Calculating the hue for the background color and changing it var hue = 200 - (parseInt(message) * 5); document.body.style.backgroundColor = "hsl(" + hue + ", 60%, 65%)"; }); </script>
你完成了! Arduino 温度读数现在将在浏览器中实时显示。
结论
虽然构建自己的硬件的前景可能令人生畏,但希望在完成这两个示例之后,您已经在考虑可能性并计划下一个项目。 许多组件与 Johnny-Five 库兼容,这意味着唯一的限制是您的想象力。
资源
- “使用 JavaScript 进行硬件黑客攻击”,James Miller 和 Mate Marshalko,GitHub
该项目所需的所有代码 - 约翰尼五号,里克沃尔德伦,GitHub
“JavaScript 机器人编程框架” - 设备上的网络,Mate Marshalko
一个使用 JavaScript 和其他网络技术进行电子黑客攻击的网站 - 制作
Maker Media 的在线杂志,针对创客,提供新项目和技巧 - Node.js 的 Arduino 实验者指南
Johnny-Five 的更多 JavaScript 和 Arduino 项目