WebSocket 支持通过网络进行实时双向通信。
WebSocket 可以与普通的 HTTP 服务器一起运行。您可以单击 Web 浏览器中的按钮,然后启用 Raspberry Pi 上的 GPIO,从而打开您家中的灯。一切都是实时的,并且是双向沟通的!
在本章中,我们将使用 WebSocket 设置一个 Web 服务器。然后创建一个浏览器 UI 来与我们之前的示例进行交互使用按钮打开和关闭 LED。
对于本教程,您需要一个 Raspberry Pi。在我们的示例中,我们使用 Raspberry Pi 3,但本教程应该适用于大多数版本。
为此,您需要:
单击上面列表中的链接以获取不同组件的说明。
笔记:您需要的电阻器可能与我们使用的不同,具体取决于您使用的 LED 类型。大多数小型 LED 仅需要一个小电阻,大约 200-500 欧姆。通常使用的具体值并不重要,但电阻值越小,LED 就会越亮。
与我们之前的示例相比,我们唯一需要的新东西是设置一个 Web 服务器,并安装 socket.io 模块。
按照本 Node.js 教程前面的章节,让我们设置一个可以提供 HTML 文件的 Web 服务器。
在我们的 "nodetest" 目录中创建一个可用于静态 html 文件的新目录:
pi@w3demopi:~/nodetest $ mkdir public
现在让我们设置一个网络服务器。创建一个 Node.js 文件,该文件打开请求的文件并将内容返回给客户端。如果出现任何问题,请抛出 404 错误。
pi@w3demopi:~/nodetest $ nano webserver.js
网络服务器.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
索引.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/ 在浏览器中打开网站:
Web 服务器现在应该已启动并正在运行,我们可以继续讨论 WebSocket 部分。
设置网络服务器后,将 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。让我们更新我们的index.html 文件:
索引.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 文件:
网络服务器.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 章节中的大量代码。
网络服务器.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
。