×

使用节点构建您自己的物联网平台

消耗积分:0 | 格式:zip | 大小:0.00 MB | 2023-06-14

分享资料个

描述

如果您是硬件爱好者,那么您可能已经通过 WiFi 使 LED 闪烁。

可能在您的本地网络上或使用 Blynk 或 ThingSpeak 等第三方服务通过互联网。

但它要么只适用于您的本地网络,要么您必须使用一些第 3 方解决方案。

在本文中,我将指导您如何构建您自己的 IoT 最小平台,该平台可在 Internet 上运行。

我们的平台将分为三个部分,

  • 用户界面即。前端
  • 服务器即后端
  • 硬件

应用程序的所有三个部分都应该能够实时相互通信。

基于硬件的产品/项目的明显协议是 MQTT。

MQTT 是一种轻量级通信协议,旨在甚至在低功耗硬件上运行。但今天我们不使用 MQTT ,为了简单和运行服务器的成本。

像 Heroku 这样的网络托管平台有很多,我们可以免费使用。您甚至不需要信用卡即可注册。

MQTT 不适用于这些 PaaS(平台即服务)提供商。

所以我们将使用下一个最好的东西,Introducing Web Sockets。

它不像 MQTT 那样简单,但我们使用的 MCU 足够强大来处理它。

下图是系统将如何通信

pYYBAGSBsleAEiv5AAATCh_cCZQ184.png
通讯图
 

现在我们已经弄清楚了协议

我们将使用我们值得信赖的老朋友 ESP8266,它非常受欢迎,价格便宜,而且很可能您身边就有一个 NodeMCU。

我们将使用 Arduino IDE 对我们的 ESP 进行编程。

现在让我们谈谈我们的服务器,我们将构建一个 node.js [添加链接] 应用程序,

我们将借助两个 node.js 库来创建我们的服务器。

用于 HTTP 连接的 express.js 和用于 WebSockets 连接的Socket.io 。

我们平台的前端是纯 HTML、CSS 和一些 JavaScript。没有什么比 React、Angular 或 Vue 更花哨的了(但你可以期待未来的教程)。

我们的 UI 很简单,它只有一个按钮,我们将使用 javascript 监听这个按钮的点击并通过 WebSockets 更新服务器。

编码时间

服务器代码走查

让我们从编码我们的服务器开始。

您需要在您的机器上下载并安装。node.js

根据操作系统,安装过程可能会有所不同。

完成此操作后,让我们克隆项目代码库。

git clone git@github.com:B45i/ESP-Websocket-Switch.git

或者你可以从GitHub下载并解压它(但要确保你已经安装git在你的机器上,我们需要它用于后面的步骤)

只想浏览代码?试试这个在线代码编辑器。

执行此操作后,在您喜欢的代码编辑器中打开新创建的文件夹,我将使用 VS Code。

你会看到这样的东西:

pYYBAGSBslmAeRwVAABqj9ZrwyU790.png
文件夹结构
 

固件文件夹有我们的 Arduino 代码,该src文件夹包含我们的服务器和 UI 代码。

package.json文件包含有关我们将需要的库的信息,尽管它没有安装在我们的文件夹中。

在终端中打开我们的项目文件夹并输入npm i (确保您的终端指向package.json文件所在的位置)

poYBAGSBslyAe5B5AABXNIonUek309.png
 

这将安装所有必要的库。

如果您查看 的script部分package.json,您会看到如下命令:

"scripts": {
        "dev": "nodemon src/app.js",
        "start": "node src/app.js"
}

我们可以通过键入npm run dev或运行这些命令npm run start

npm run dev将以开发模式运行我们的服务器,即,它将监听任何文件更改并重新运行服务器。

amal@Amals-MacBook-Pro esp-socket % npm run dev
> esp-socket@1.0.0 dev
> nodemon src/app.js
[nodemon] 2.0.19
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/app.js`
Running on :  { address: '::', family: 'IPv6', port: 4001 }

您可以通过打开应用程序来查看http://localhost:4001/

poYBAGSBsl-ATNtQAABoXtEhrxs098.png
 

当我们部署代码时,服务器将使用npm run start命令运行。

这两个命令都指向文件夹app.js中。src

我们来看看那个文件。

app.js文件是这样开始的

import express from 'express';
import http from 'http';
import { Server } from 'socket.io';

在这里,我们将导入我们将要使用的所有库。

请注意,我在这里使用 ES6 导入语句,在package.json文件中设置typemodule启用此功能。

当我们将代码部署到像 Heroku 这样的平台时,我们的服务器将要运行的端口将来自一个名为PORT.

const PORT = process.env.PORT || 4001;

在本地,环境变量将为空,因此如果它为空,我们将端口设置为4001.

现在让我们配置 express(node.js HTTP 框架)和Socket.io(WebSocket 库)

const app = express();
const httpServer = http.createServer(app);
const io = new Server(httpServer, { cors: { origin: '*' } });

当浏览器发送请求时,我们需要发送我们的 UI HTML / CSS 和 Javascript 文件。

这是使用 expresse 的静态中间件完成的

app.use(express.static('src/ui'));

我们需要在服务器中维护按钮的状态,这是使用buttonState.

let buttonState = false;

其余代码用于管理我们的 WebSocket 连接。

io.on('connection', socket => {
	console.log('New Connection');
	io.to(socket.id).emit('buttonState', buttonState);
	.
	.
	.
}

当新的 WS 客户端连接到服务器时,将执行此代码。

在这个箭头函数中,我们将编写其余与 WS 相关的代码。

WebSocket 是基于事件的,每当你想发送一些数据时,你将它作为一个事件传播,并附加一些信息。

当我们查看我们的 UI 代码时,这将更加清晰。

我们需要在客户加入时告诉他们按钮的当前状态,以便他们可以同步。

io.to(socket.id).emit('buttonState', buttonState);

这段代码获取新加入的客户端的 ID,并将按钮的当前状态发送给它。

connection回调函数里面,可以看到各种WebSocket事件相关的代码

socket.on('disconnect', () => {
        console.log('Disconnected');
    });

    socket.on('buttonState', value => {
				buttonState = value;
        socket.broadcast.emit('buttonState', value);
    });

第一个是disconnect当客户端断开连接时的事件,这个事件被触发,我们现在不打算使用这个事件。

socket.on('buttonState', value => {
	 			buttonState = value;
        socket.broadcast.emit('buttonState', value);
    });

这是负责连接我们的 UI 和硬件的代码。

当用户单击 UI 上的按钮时,我们的前端 javascript 代码会触发一个事件 ( buttonState)

这将执行上面的代码。

首先,我们将更新buttonState变量,然后获取该值并将其发送给所有其他客户端,除了使用它的来源socket.broadcast.emit('buttonState', value);

我们需要在指定的端口(4001在本地)上提供我们的 express 应用程序,这段代码正是这样做的。

UI 代码演练

我们的 UI 代码驻留在src/ui文件夹中。

您将看到三个文件,index.htmlindex.js并且style.css

HTML 和 CSS 文件非常基本,它只包含按钮和样式。

那么让我们看一下JS文件。

我们需要初始化socket.io对象,这是通过调用io()函数来完成的。

const socket = io();

我们需要使用 JS 获取按钮元素,以便我们可以为其附加事件监听器。

const toggleBtn = document.getElementById('toggleBtn');

我们将声明一个名为的变量buttonState,它代表 UI 中按钮的状态,当用户单击该按钮时,我们将翻转该变量的值。

现在我们将附加一个点击事件并监听这些按钮点击。

toggleBtn.addEventListener('click', () => {
    buttonState = !buttonState;
    updateUI();
    socket.emit('buttonState', buttonState);
});

如果它是真的,我们将否定变量值然后它变成假的。buttonState反之亦然。

然后我们调用该updateUI()函数(我们稍后会看一下这个函数)

到目前为止,我们的更改是在 UI 本身上进行的,服务器并不知道它。

我们需要告诉我们的服务器关于新的更新,为此我们将使用

socket.emit('buttonState', buttonState)功能。

这将告知服务器我们 UI 的更改,服务器会将此更改广播给其他客户端。

当用户单击按钮时,根据状态,它的颜色和文本会发生变化。

如果按钮关闭,那么它将是红色的,当它打开时它将是绿色的。

updateUI负责此更改。

const updateUI = () => {
    buttonState
        ? toggleBtn.classList.add('on')
        : toggleBtn.classList.remove('on');
    toggleBtn.innerText = buttonState ? 'Turn off' : 'Turn on';
};

如果 的值为toggleBtntrue 则我们添加一个 CSS 类,on否则我们将其删除。这个类负责颜色。

我们还根据值更改按钮内的文本。

如果您npm run dev在终端中运行命令并localhost:4001在浏览器中打开,您应该能够看到我们的应用程序 UI。

如果您在多个选项卡中打开相同的地址,您可以看到当您单击另一个选项卡上的按钮时,一个选项卡中的 UI 会自动更新。

同时变化

部署服务器

我们的应用程序正在运行,但它在我们的本地机器上,我们需要部署它以便它可以在互联网上的任何地方使用。

我们将使用一个名为Heroku的平台来托管我们的应用程序。

从 Heroku 创建一个免费帐户:https ://signup.heroku.com/dc

heroku clihttps://devcenter.heroku.com/articles/heroku-cli安装

我们将使用此命令行实用程序来管理我们的应用程序。

通过在终端中键入命令,确保git和 Heroku 已成功安装在您的计算机上。heroku

pYYBAGSBsmGARcPwAAGs9JxhQv8432.png
heroku命令的输出'
 

现在 CLI 不知道您创建的帐户,要连接您的 CLI 和帐户,请heroku login在终端中键入,这将打开一个浏览器窗口,您可以从中登录到您的 Heroku 帐户。

heroku login
heroku: Press any key to open up the browser to login or q to exit
 ›   Warning: If browser does not open, visit
 ›   https://cli-auth.heroku.com/auth/browser/***
heroku: Waiting for login...
Logging in... done
Logged in as me@example.com

现在让我们在我们的 Heroku 帐户上创建一个应用程序

heroku create

这将创建一个 Heroku 应用程序,我们可以在其中托管我们的代码。

heroku create
Creating sharp-rain-871... done, stack is heroku-18
http://sharp-rain-871.herokuapp.com/ | https://git.heroku.com/sharp-rain-871.git
Git remote heroku added

将我们的代码部署到 Heroku 非常简单,我们可以使用一个命令来完成。

git push heroku main

此命令执行完毕后,我们的代码将部署到互联网上。

git push heroku main
Counting objects: 488, done.
Delta compression using up to 8 threads.
.
.
.
.
remote: Verifying deploy... done.
To https://git.heroku.com/nameless-savannah-4829.git
 * [new branch]      main -> main

为确保我们的应用程序至少有一个实例正在运行,请运行以下命令:

heroku ps:scale web=1

要打开我们的 Web 应用程序,请运行heroku open,这将在浏览器中打开我们应用程序的 URL。

您应该可以从互联网上的任何地方打开它。

如果您从另一台设备打开此 URL,您可以看到 UI 在您单击另一台设备上的按钮时实时更新。

在两个浏览器上运行的应用程序

硬件代码

现在我们将使用 Arduino IDE 对 ESP8266 微控制器进行编码。

确保您已经在 Arduino IDE 上安装了ESP8266 核心和必要的库。

该项目所需的库:

在 Arduino IDE 上打开文件。firmware/firmware.io

您必须稍微自定义此代码。

#define SSID "Your WiFi SSID"
#define PASSWORD "Your WiFi password"
#define SERVER "esp-socket-switch.herokuapp.com"  // Server URL (without )

SSID是您的 WiFi 名称,PASSWORD是您的 wifi 密码。

您需要复制键入时获得的 URLheroku open并将其粘贴为SERVER.

确保URL 中没有。

我们需要创建一个 SocketIOclient 类的对象

SocketIOclient socketIO;

该对象将管理我们 MCU 上的 WebSocket 连接。

现在让我们看一下setup函数,这里我们将连接到 WiFi,注册输出引脚和Socket.IO事件处理程序。

为了简单起见,我将使用 NodeMCU 的板载 LED,如果需要,您可以连接一个外部 LED。

PS:NodeMCU 上的板载 LED 是倒置的,即当引脚为低电平时它会亮起。
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);

希望每个人都熟悉这段代码的作用,我们将我们的引脚设置为输出并设置串口连接的波特率。

现在我们将调用setupWiFi() 函数,它将 MCU 连接到您指定的 WiFi SSID。

接下来的两行与Socket.IO有关

socketIO.begin(SERVER, 80, "/socket.io/?EIO=4");
socketIO.onEvent(socketIOEvent);

在这里我们将尝试连接到 WebSocket 服务器,并注册Socket.IO事件处理程序。

socketIOEvent是我们的事件处理函数,现在让我们看一下。

void socketIOEvent(socketIOmessageType_t type, uint8_t* payload, size_t length) {
  switch (type) {
    case sIOtype_DISCONNECT:
      Serial.println("Disconnected!");
      break;

    case sIOtype_CONNECT:
      Serial.printf("Connected to url: %s%s\\n", SERVER, payload);
      socketIO.send(sIOtype_CONNECT, "/");
      break;

    case sIOtype_EVENT:
      messageHandler(payload);
      break;
  }
}

在这个函数中,你可以看到一个 switch 语句,我们现在甚至没有使用连接和断开连接。

但是对于 sIOtype_EVENT事件,我们正在调用messageHandler函数,它会解析事件数据。

void messageHandler(uint8_t* payload) {
  StaticJsonDocument<64> doc;

  DeserializationError error = deserializeJson(doc, payload);

  if (error) {
    Serial.println(error.f_str());
    return;
  }

  String messageKey = doc[0];
  bool value = doc[1];

  if (messageKey == "buttonState") {
    digitalWrite(LED_BUILTIN, value);
  }
}

在此消息处理程序中,我们尝试解析随事件收到的 JSON 数据。

解析后的数据将在doc变量中,doc[0]将包含事件名称并doc[1]具有值。

如果密钥是,buttonState那么我们会将引脚状态切换为从服务器获得的值。

现在,当我们单击 UI 上的按钮时,LED 应该打开和关闭。

poYBAGSBsm2Acpi0ABqT-nSLRNQ67.jpeg
 

我希望这个小教程能帮助您学到新东西。


声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

评论(0)
发评论

下载排行榜

全部0条评论

快来发表一下你的评论吧 !