Node.js và Raspberry Pi - Máy chủ web với WebSocket
WebSocket là gì?
WebSocket cho phép giao tiếp hai chiều trong thời gian thực qua web.
WebSocket có thể chạy cùng với máy chủ HTTP thông thường. Bạn có thể nhấp vào nút trong trình duyệt web và bật GPIO trên Raspberry Pi để bật đèn trong nhà bạn. Tất cả đều diễn ra trong thời gian thực và với khả năng giao tiếp theo cả hai chiều!
Trong chương này, chúng ta sẽ thiết lập một máy chủ web với WebSocket. Sau đó, tạo giao diện người dùng trình duyệt để tương tác với ví dụ trước đây của chúng tôi về việc bật và tắt đèn LED bằng một nút .
Tôi cần những gì?
Đối với hướng dẫn này, bạn cần có Raspberry Pi. Trong các ví dụ của chúng tôi, chúng tôi sử dụng aa Raspberry Pi 3, nhưng hướng dẫn này sẽ hoạt động với hầu hết các phiên bản.
Đối với điều này bạn cần:
- Một Raspberry Pi có Raspian, internet, SSH, đã cài đặt Node.js
- Mô-đun bật tắt cho Node.js
- Mô-đun socket.io cho Node.js
- 1 x Bảng mạch
- Điện trở 1 x 68 Ohm
- Điện trở 1 x 1k Ohm
- 1 x Đèn LED xuyên lỗ
- 1 x Nút ấn
- 4 x dây nhảy từ nữ sang nam
- 1 x dây nhảy từ Đực sang Đực
Nhấp vào các liên kết trong danh sách ở trên để xem mô tả về các thành phần khác nhau.
Lưu ý: Điện trở bạn cần có thể khác với điện trở chúng tôi sử dụng tùy thuộc vào loại đèn LED bạn sử dụng. Hầu hết các đèn LED nhỏ chỉ cần một điện trở nhỏ, khoảng 200-500 ohm. Nói chung, giá trị chính xác bạn sử dụng không quan trọng, nhưng giá trị của điện trở càng nhỏ thì đèn LED sẽ càng sáng.
So với ví dụ trước đó của chúng tôi, điều mới duy nhất chúng tôi cần là thiết lập máy chủ web và cài đặt mô-đun socket.io.
Máy chủ web cho Raspberry Pi và Node.js
Tiếp theo các chương trước trong hướng dẫn Node.js này, hãy thiết lập một máy chủ web có thể phân phát các tệp HTML.
Trong thư mục "nodetest" của chúng tôi, hãy tạo một thư mục mới mà chúng tôi có thể sử dụng cho các tệp html tĩnh:
pi@w3demopi:~/nodetest $
mkdir public
Bây giờ hãy thiết lập một máy chủ web. Tạo tệp Node.js để mở tệp được yêu cầu và trả về nội dung cho máy khách. Nếu có vấn đề gì xảy ra, hãy đưa ra lỗi 404.
pi@w3demopi:~/nodetest $
nano webserver.js
máy chủ web.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();
});
}
Chuyển đến thư mục "công khai":
pi@w3demopi:~/nodetest $
cd public
Và tạo một tệp HTML, index.html:
pi@w3demopi:~/nodetest/public $
nano index.html
chỉ mục.html:
<!DOCTYPE html>
<html>
<body>
<h1>Control LED light</h1>
<input
id="light" type="checkbox">LED
</body>
</html>
Tập tin này sẽ không có bất kỳ chức năng nào. Hiện tại nó chỉ là một phần giữ chỗ. Hãy xem máy chủ web có hoạt động không:
pi@w3demopi:~/nodetest/public $ cd ..
pi@w3demopi:~/nodetest $ node webserver.js
Mở trang web trong trình duyệt bằng https://[RaspberryPi_IP]:8080/:
Máy chủ web hiện đã hoạt động và chúng ta có thể chuyển sang phần WebSocket.
Cài đặt socket.io cho Node.js
Sau khi thiết lập máy chủ web, hãy cập nhật các gói hệ thống Raspberry Pi của bạn lên phiên bản mới nhất.
Cập nhật danh sách gói hệ thống của bạn:
pi@w3demopi:~ $ sudo apt-get update
Nâng cấp tất cả các gói đã cài đặt của bạn lên phiên bản mới nhất:
pi@w3demopi:~ $ sudo apt-get dist-upgrade
Làm điều này thường xuyên sẽ giúp cài đặt Raspberry Pi của bạn được cập nhật.
Để tải xuống và cài đặt phiên bản socket.io mới nhất, hãy sử dụng lệnh sau:
pi@w3demopi:~ $
npm install socket.io --save
Thêm WebSocket vào máy chủ web của chúng tôi
Bây giờ chúng ta có thể sử dụng WebSocket trong ứng dụng của mình. Hãy cập nhật tệp index.html của chúng tôi:
chỉ mục.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>
Và tệp webserver.js của chúng tôi:
máy chủ web.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
}
});
});
Hãy kiểm tra máy chủ:
pi@w3demopi:~ $
node webserver.js
Mở trang web trong trình duyệt bằng https://[RaspberryPi_IP]:8080/:
Bây giờ máy chủ sẽ xuất tất cả các thay đổi đối với hộp kiểm ra bảng điều khiển trên Raspberry Pi.
Máy khách đang gửi các thay đổi đến máy chủ và máy chủ đang phản hồi.
Hãy thêm đèn LED điều khiển bằng nút nhấn từ chương trước.
Thêm phần cứng và gửi phản hồi cho Khách hàng
Hãy cập nhật lại tệp webserver.js của chúng tôi. Chúng ta sẽ sử dụng rất nhiều mã từ chương LED điều khiển bằng nút nhấn.
máy chủ web.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
});
Hãy kiểm tra máy chủ:
pi@w3demopi:~ $ node webserver.js
Mở trang web trong trình duyệt bằng https://[RaspberryPi_IP]:8080/:
Bây giờ máy chủ sẽ xuất tất cả các thay đổi đối với hộp kiểm ra bảng điều khiển trên Raspberry Pi.
Máy khách đang gửi các thay đổi đến máy chủ và máy chủ đang phản hồi.
Kết thúc chương trình bằng Ctrl+c
.