Node.js 和 树莓派(Raspberry Pi) - 带有 WebSocket 的 Web 服务器
什么是 WebSocket?
WebSocket 支持通过网络实时进行双向通信。
WebSocket 可以与普通的 HTTP 服务器一起运行。 您可以在 Web 浏览器中单击一个按钮,然后在您的树莓派(Raspberry Pi) 上启用一个 GPIO,它会打开您家中的灯。 一切都是实时的,双向沟通!
在本章中,我们将使用 WebSocket 建立一个 Web 服务器。 然后创建一个浏览器 UI 以与我们之前的使用按钮打开和关闭 LED 的示例进行交互。
我需要什么?
对于本教程,您需要一个树莓派(Raspberry Pi)。 在我们的示例中,我们使用的是树莓派(Raspberry Pi) 3,但本教程应该适用于大多数版本。
为此,您需要:
- 一个带有 Raspian、互联网、SSH 和 Node.js 的树莓派(Raspberry Pi)
- The onoff module for Node.js
- The socket.io module for Node.js
- 1 x Breadboard
- 1 x 68 Ohm resistor
- 1 x 1k Ohm resistor
- 1 x Through Hole LED
- 1 x Push Button
- 4 x Female to male jumper wires
- 1 x Male to Male jumper wires
单击上面列表中的链接了解不同组件的说明。
注释:您需要的电阻器可能与我们使用的电阻器不同,具体取决于您使用的 LED 类型。 大多数小型 LED 只需要一个小电阻,大约 200-500 欧姆。 您使用的确切值通常并不重要,但电阻值越小,LED 就会越亮。
与我们之前的示例相比,我们唯一需要做的就是设置一个 Web 服务器,并安装 socket.io 模块。
用于树莓派(Raspberry Pi) 和 Node.js 的网络服务器
按照本 Node.js 教程中的前面章节,让我们设置一个可以提供 HTML 文件的 Web 服务器。
在我们的 "nodetest" 目录中创建一个新目录,我们可以将其用于静态 html 文件:
pi@w3demopi:~/nodetest $
mkdir public
现在让我们设置一个网络服务器。 创建一个 Node.js 文件,该文件打开请求的文件并将内容返回给客户端。 如果出现任何问题,抛出 404 错误。
pi@w3demopi:~/nodetest $
nano webserver.js
webserver.js:
var http = require('http').createServer(handler); //require http server, and
create server with function handler()
var fs = require('fs'); //require filesystem module
http.listen(8080); //listen to port 8080
function handler (req, res) { //create server
fs.readFile(__dirname + '/public/index.html', function(err, data) { //read
file index.html in public folder
if (err)
{
res.writeHead(404,
{'Content-Type': 'text/html'}); //display 404 on error
return res.end("404 Not Found");
}
res.writeHead(200, {'Content-Type': 'text/html'}); //write HTML
res.write(data); //write data from index.html
return res.end();
});
}
转到文件夹 "public":
pi@w3demopi:~/nodetest $
cd public
创建一个HTML文件, index.html:
pi@w3demopi:~/nodetest/public $
nano index.html
index.html:
<!DOCTYPE html>
<html>
<body>
<h1>Control LED light</h1>
<input
id="light" type="checkbox">LED
</body>
</html>
这个文件还没有任何功能。 现在它只是一个占位符。 让我们看看网络服务器是否正常工作:
pi@w3demopi:~/nodetest/public $ cd ..
pi@w3demopi:~/nodetest $ node webserver.js
使用 http://[RaspberryPi_IP]:8080/ 在浏览器中打开网站:
网络服务器现在应该已启动并运行,我们可以继续进行 WebSocket 部分。
为 Node.js 安装 socket.io
设置好网络服务器后,将您的树莓派(Raspberry Pi) 系统包更新到最新版本。
更新你的系统包列表:
pi@w3demopi:~ $ sudo apt-get update
将所有已安装的软件包升级到最新版本:
pi@w3demopi:~ $ sudo apt-get dist-upgrade
定期执行此操作将使您的树莓派(Raspberry Pi) 安装保持最新状态。
要下载和安装最新版本的 socket.io,请使用以下命令:
pi@w3demopi:~ $
npm install socket.io --save
将 WebSocket 添加到我们的 Web 服务器
现在我们可以在我们的应用程序中使用 WebSocket。 让我们更新我们的 index.html 文件:
index.html:
<!DOCTYPE html>
<html>
<body>
<h1>Control LED
light</h1>
<p><input type="checkbox" id="light"></p>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
<!-- include socket.io client side script -->
<script>
var socket = io();
//load socket.io-client and connect to the host that serves the page
window.addEventListener("load", function(){ //when page loads
var
lightbox = document.getElementById("light");
lightbox.addEventListener("change", function() { //add event listener for
when checkbox changes
socket.emit("light", Number(this.checked));
//send button status to server (as 1 or 0)
});
});
socket.on('light',
function (data) { //get button status from client
document.getElementById("light").checked = data; //change checkbox according
to push button on树莓派(Raspberry Pi)
socket.emit("light", data); //send
push button status to back to server
});
</script>
</body>
</html>
还有我们的 webserver.js 文件:
webserver.js:
var http = require('http').createServer(handler); //require http server, and
create server with function handler()
var fs = require('fs'); //require filesystem module
var io
= require('socket.io')(http) //require socket.io module and pass the http
object (server)
http.listen(8080); //listen to port 8080
function handler (req, res) { //create server
fs.readFile(__dirname + '/public/index.html', function(err, data) { //read
file index.html in public folder
if (err)
{
res.writeHead(404,
{'Content-Type': 'text/html'}); //display 404 on error
return res.end("404 Not Found");
}
res.writeHead(200, {'Content-Type': 'text/html'}); //write HTML
res.write(data); //write data from index.html
return res.end();
});
}
io.sockets.on('connection', function (socket) {// WebSocket Connection
var lightvalue = 0; //static variable for current status
socket.on('light',
function(data) { //get light switch status from client
lightvalue = data;
if (lightvalue) {
console.log(lightvalue); //turn LED on or off, for now we will just show it
in console.log
}
});
});
让我们测试服务器:
pi@w3demopi:~ $
node webserver.js
使用 http://[RaspberryPi_IP]:8080/ 在浏览器中打开网站:
现在服务器应该将复选框的所有更改输出到树莓派(Raspberry Pi) 上的控制台。
客户端正在向服务器发送更改,服务器正在响应。
让我们添加上一章中的按钮控制的 LED。
添加硬件,并向客户端发送响应
让我们再次更新我们的 webserver.js 文件。 我们将使用按钮控制 LED 章节中的大量代码。
webserver.js:
var http = require('http').createServer(handler); //require http server, and
create server with function handler()
var fs = require('fs'); //require filesystem module
var io
= require('socket.io')(http) //require socket.io module and pass the http
object (server)
var Gpio = require('onoff').Gpio; //include onoff to
interact with the GPIO
var LED = new Gpio(4, 'out'); //use GPIO pin 4 as
output
var pushButton = new Gpio(17, 'in', 'both'); //use GPIO pin 17 as
input, and 'both' button presses, and releases should be handled
http.listen(8080); //listen to port 8080
function handler (req, res)
{ //create server
fs.readFile(__dirname
+ '/public/index.html', function(err, data) { //read file index.html in
public folder
if (err) {
res.writeHead(404, {'Content-Type': 'text/html'}); //display 404 on error
return res.end("404 Not Found");
}
res.writeHead(200, {'Content-Type': 'text/html'}); //write HTML
res.write(data); //write data from index.html
return res.end();
});
}
io.sockets.on('connection', function (socket) {// WebSocket Connection
var lightvalue = 0; //static variable for current status
pushButton.watch(function (err, value) { //Watch for hardware interrupts on
pushButton
if (err) { //if an error
console.error('There was an error', err); //output error message to console
return;
}
lightvalue = value;
socket.emit('light', lightvalue); //send button status to client
});
socket.on('light', function(data) { //get light switch status
from client
lightvalue = data;
if (lightvalue != LED.readSync()) { //only change LED if status has changed
LED.writeSync(lightvalue); //turn LED on or off
}
});
});
process.on('SIGINT', function () { //on ctrl+c
LED.writeSync(0); // Turn LED off
LED.unexport(); // Unexport LED
GPIO to free resources
pushButton.unexport(); // Unexport Button
GPIO to free resources
process.exit(); //exit completely
});
让我们测试服务器:
pi@w3demopi:~ $ node webserver.js
使用 http://[RaspberryPi_IP]:8080/ 在浏览器中打开网站:
现在服务器应该将复选框的所有更改输出到树莓派(Raspberry Pi) 上的控制台。
客户端正在向服务器发送更改,服务器正在响应。
用 Ctrl+c
结束程序。