如果您是硬件爱好者,那么您可能已经通过 WiFi 使 LED 闪烁。
可能在您的本地网络上或使用 Blynk 或 ThingSpeak 等第三方服务通过互联网。
但它要么只适用于您的本地网络,要么您必须使用一些第 3 方解决方案。
在本文中,我将指导您如何构建您自己的 IoT 最小平台,该平台可在 Internet 上运行。
我们的平台将分为三个部分,
应用程序的所有三个部分都应该能够实时相互通信。
基于硬件的产品/项目的明显协议是 MQTT。
MQTT 是一种轻量级通信协议,旨在甚至在低功耗硬件上运行。但今天我们不使用 MQTT ,为了简单和运行服务器的成本。
像 Heroku 这样的网络托管平台有很多,我们可以免费使用。您甚至不需要信用卡即可注册。
MQTT 不适用于这些 PaaS(平台即服务)提供商。
所以我们将使用下一个最好的东西,Introducing Web Sockets。
它不像 MQTT 那样简单,但我们使用的 MCU 足够强大来处理它。
下图是系统将如何通信
现在我们已经弄清楚了协议
我们将使用我们值得信赖的老朋友 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。
你会看到这样的东西:
固件文件夹有我们的 Arduino 代码,该src
文件夹包含我们的服务器和 UI 代码。
package.json
文件包含有关我们将需要的库的信息,尽管它没有安装在我们的文件夹中。
在终端中打开我们的项目文件夹并输入npm i
(确保您的终端指向package.json
文件所在的位置)
这将安装所有必要的库。
如果您查看 的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/
当我们部署代码时,服务器将使用npm run start
命令运行。
这两个命令都指向文件夹app.js
中。src
我们来看看那个文件。
app.js
文件是这样开始的
import express from 'express';
import http from 'http';
import { Server } from 'socket.io';
在这里,我们将导入我们将要使用的所有库。
请注意,我在这里使用 ES6 导入语句,在package.json
文件中设置type
为module
启用此功能。
当我们将代码部署到像 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 代码驻留在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';
};
如果 的值为toggleBtn
true 则我们添加一个 CSS 类,on
否则我们将其删除。这个类负责颜色。
我们还根据值更改按钮内的文本。
如果您npm run dev
在终端中运行命令并localhost:4001
在浏览器中打开,您应该能够看到我们的应用程序 UI。
如果您在多个选项卡中打开相同的地址,您可以看到当您单击另一个选项卡上的按钮时,一个选项卡中的 UI 会自动更新。
我们的应用程序正在运行,但它在我们的本地机器上,我们需要部署它以便它可以在互联网上的任何地方使用。
我们将使用一个名为Heroku的平台来托管我们的应用程序。
从 Heroku 创建一个免费帐户:https ://signup.heroku.com/dc
heroku cli
从https://devcenter.heroku.com/articles/heroku-cli安装
我们将使用此命令行实用程序来管理我们的应用程序。
通过在终端中键入命令,确保git和 Heroku 已成功安装在您的计算机上。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 应该打开和关闭。
我希望这个小教程能帮助您学到新东西。
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
全部0条评论
快来发表一下你的评论吧 !