IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 利用nodemcu和mqtt协议让嵌入式设备接入互联网(三.实现数据交互) -> 正文阅读

[嵌入式]利用nodemcu和mqtt协议让嵌入式设备接入互联网(三.实现数据交互)

前言

我们已经搭建好了开发环境,并且已经设计好了UI界面,现在就要正式编写后端软件,来进行数据交互。先来介绍这些第三方依赖包。

KOA2框架

基于nodejs的web框架有很多,讨论最多的就是express和koa2,express生态最好,用的最多,而koa2是express的原班人马打造,相当于express的升级版。我个人的原则是:学就学最新的,除非学不会。所以我选用koa2框架。
推荐B站这个教程,koa教程,说实话因为之前没接触过web相关的知识,理解这些路由和中间件等概念,还是让我头痛了一阵,就算现在我也不能保证我理解的完全正确,但基本能实现我现在想要的功能,欢迎指正批评。而且想学好KOA和nodejs还是要花费很多功夫的,我目前这样的浅尝辄止的程度还是不够的,有机会继续深入研究。
在这篇文章中不系统总结(还没学到位),只解释我用到的一些东西。

koa2初步使用

我们现在项目目录中新建一个index.js文件,然后键入以下代码

//引入Koa
const koa=require('koa');
const app=new koa();
//配置中间件
app.use( async (ctx)=>{
 ctx.body='hello koa2'
})
//监听端口
app.listen(3000);
//本地终端打印log
console.log('[demo] start-quick is starting at port 3000')

然后在浏览器中访问localhost:3000或者127.0.0.1:3000(一个意思),可以看到,字符串’hello koa2’就出现在网页中了。

在这里插入图片描述PS :

  • javascript的字符串可以用单引号也可以用双引号。
  • javascript每条语句可以不加分号,只敲回车,也能正常运行,但最好加。因为不是不需要分好,而是JS剖析器会在执行期间自动帮你插入分号。

koa示例代码解释

引入模块用require,require是CommonJS规范引入模块的方法,而对于最新的ES6规范,引入模块的方法是import,关于这两种规范引入模块方法的错杂和历史以后我有机会再整理。我们只跟着npm官网,包的使用教程来使用,npm官网koa,官网怎么用,我们怎么用。引用模块后,再用new关键字,对模块进行实例化。
在这里插入图片描述

//配置中间件
app.use( async (ctx)=>{
 ctx.body='hello koa2'
})

这里的中间件的概念,官方没给定义,koa中文网给的解释是

中间件就是匹配路由之前或者匹配路由完成做的一系列的操作,我们就可以把它叫做中间件

我的理解是,中间件就是一个插件,也可以理解为一个函数。当用户请求时,要经过中间件的处理,生成响应时也要经过中间件的处理,处理顺序符合洋葱模型详细解释

在这里插入图片描述

和=>这种匿名函数的写法,都请移步到B站的视频学习koa教程
最后使用app.listen方法,对3000端口进行监听。这个函数必须调用,否则浏览器访问网址时,发出的GET、POST请求都无法响应,那么我的网址也是无法访问的。

//监听端口
app.listen(3000);

要注意nodejs的编程,不同于C或其他的一些语言顺序性、过程性比较强,nodejs更偏向于事件驱动,函数调用也都是异步的,如果想同步,顺序的执行某些回调函数,就得用asyncawait的组合。

koa-static中间件

koa-static是一个用来加载静态资源的中间件,我们第一章写的index.html文件想要它通过访问网址,加载到网页上,就需要用koa-static这个中间件,首先我们去看npm官网的例子

const serve = require('koa-static');
const Koa = require('koa');
const app = new Koa();
 
// $ GET /package.json
app.use(serve('.'));
 
// $ GET /hello.txt
app.use(serve('test/fixtures'));
 
// or use absolute paths
app.use(serve(__dirname + '/test/fixtures'));
 
app.listen(3000);
 
console.log('listening on port 3000');

上面的官方例子代表了koa-static中间件访问静态资源的三种情况,第一种访问当前目录,在当前目录找index.html这个文件,然后显示到网页中去。第二种访问相对路径,test/fixtures文件夹下找index.html这个文件。第三种绝对路径,__dirname是nodejs全局对象,代表的是当前目录。

Aedes

Aedes是一个Stream-based MQTT broker,基于流的MQTT代理,所谓broker(代理),可以理解为服务器,所有的mqtt节点的话题发布和订阅都要经过broker。关于MQTT代理,还有一个包是mosca,也能起到相同的作用。mosca和Aedes是同一个人开发的,github网址moscajs,只不过mosca已经不维护了,Aedes是mosca的升级版本。

mqtt协议

MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。

mqtt的协议的工作方式就如下图,broker类似于一个平台,任何机器都可以在平台上发布话题(Publish),任何机器也可以订阅想要看到的话题(Subscribe),这要就能使得每个支持mqtt协议的设备网络互联,实现所谓的万物互联。这里有一个Qos(服务质量等级)的概念,有Qos0、Qos1、Qos2三个等级。

质量等级解释
Qos0发送者只发一次
Qos1发送者至少发送一次,确保broker收到
Qos2发送者至少发送一次,确保broker收到,且只收到一次

这里的Qos2只是理想,并没有broker支持。

在这里插入图片描述

用aedes创建broker并测试

参考github的aedes官方库的示例链接,我们直接在index.js敲以下代码,然后在终端启动,命令
node .\index.js

const aedes = require('aedes')()
const server = require('net').createServer(aedes.handle)
const port = 1883

server.listen(port, function () {
  console.log('server started and listening on port ', port)
})

这里我们已经启动了一个broker,我们再利用工具来测试一下,windows10电脑端,在应用商店下载MQTTBox这个应用,点击creat mqtt client后,填入我们的Ip地址和端口号,协议选择mqtt/tcp。
在这里插入图片描述
保存设置后,来到下面这个页面,左边发布个mytopic话题,填入数据,右边我们订阅自己发布的话题。点击发布,就可以收到信息了。
在这里插入图片描述
当然,我们也可以用其他客户端进行订阅,在手机应用商店搜索mqtt,我用的是EasyMQTT这个APP,填入broker的ip和端口号,手机同样能收到MQTTBox发布的mytopic话题的信息。
在这里插入图片描述

MQTT server over WebSocket

我们已经搭建出了mqtt的broker,现在就要考虑怎么将mqtt的话题里的payload传递到web端。

http协议和websocket

web网页常用的通讯协议是HTTP和websocket。像我们前面使用koa中间件发送"hello koa2"字符串,虽然这里面经过了koa2的封装,我们看不到http协议的请求和响应,但这实际上就是一个基于http协议的通讯。
例如这个例子,我们用浏览器访问3000端口,发现我们的请求时GET,response是"hello koa2"。

在这里插入图片描述
response是"hello koa2"

在这里插入图片描述
ps: 这里的favicon.ico,是去请求小图标,小图标就是浏览器每个标签上左侧的小图标。

在这里插入图片描述
包括后面koa-static中间件,也是封装了http协议,去请求一个静态的页面。HTTP协议是一个单向协议,客户端放松请求(GET/POST),服务器发送响应,当连接的速度要求不高和只请求一次的场景下,使用HTTP协议。 当需要服务器主动向客户端推送消息,并且连接速度需要比较快,数据需要经常更新的场景下,我们使用的就应该是websocket协议了。

mqtt over websocket

对于我们这个场景,每个nodemcu都是一个mqtt客户端,web网页也应该是一个mqtt客户端,nodejs既是mqtt的broker(代理),也是web网页的服务器。用nodejs 的好处就凸显出来了,我们可以将mqtt的broker和web服务器,写在同一个nodejs脚本里。首先我们看官方例程
在这里插入图片描述
例程中的ws.createServer({server:httpServer},aedes.handle),我在其git仓库中没有找到响应的解释,但通过试验,其功能应该是将mqtt协议的信息流传给websocket的信息流。
ps:var=require('模块')()等价于先引用模块,再实例化。但并不是所有的模块都支持这种写法,应该与封装导出的方式相关。

//下面两行等效于 
aedes=require('aedes')();
// const Aedes = require('aedes');
// var aedes=new Aedes();

后端

koa、koa-static、aedes、websocket-stream这三个依赖包都讲了下,可以开始写我们的nodejs程序了。
这里我们用到3个端口,1883端口用于mqtt broker,8888用于http模块创建的websocket,5000端口用于koa2创建的http服务器。其实应该可以直接用koa2框架里的工具来创建websocket的,但是我这里暂时是修改的官方例子,没有去探究怎么用koa2来实现websocket通讯。
其实这里面有两个http服务器,一个是8888端口,只用于websoket的。一个是5000端口,用于koa2加载静态资源的。有时间,会去把他们简化一些。

const Koa = require('koa');
const static = require('koa-static');
//const path = require('path');
//--------------------------------------------//
//下面两行等效于 
aedes=require('aedes')();
// const Aedes = require('aedes');
// var aedes=new Aedes();
//--------------------------------------------//
//-----------------------MQTT broker creat----------------------- 

const broker = require('net').createServer(aedes.handle);
const httpServer = require('http').createServer();
const ws = require('websocket-stream');
const port = 1883;
const wsPort = 8888;

broker.listen(port, function () {
  console.log('broker listening on port', port)
});

ws.createServer({
  server: httpServer
}, aedes.handle);

httpServer.listen(wsPort, function () {
  console.log('websocket server listening on port', wsPort)
});

//身份验证
aedes.authenticate = function (client, username, password, callback) {
    callback(null, (username === 'user' && password.toString() === '123456'));
};

// 客户端连接
aedes.on('client', function (client) {
    console.log('Client Connected: \x1b[33m' + (client ? client.id : client) + '\x1b[0m', 'to broker', aedes.id);
});
// 客户端断开
aedes.on('clientDisconnect', function (client) {
    console.log('Client Disconnected: \x1b[31m' + (client ? client.id : client) + '\x1b[0m', 'to broker', aedes.id);
});

//-----------------------MQTT broker creat----------------------- 

var app = new Koa();
//const staticPath = './static';
//app.use(static(path.join(__dirname, staticPath)));
app.use(static('./static'));

app.listen(5000, () => { console.log('server start on port 5000'); });

至此,我们的后端和前端就都搭建好了,可以先脱离nodemcu硬件,用MQTTBox或者手机端的进行数据交互的测试。

前端脚本

第一章我们我们搭建好了UI,引入了两个脚本。其中mqtt.min.js是在npm库unpkg网站上下载的,当然我们也可以用下面注释的方式来引用它。这个脚本的作用,是让我们可以在前端的javascript脚本里使用mqtt协议。

	<!-- <script src="https://unpkg.com/mqtt@4.2.8/dist/mqtt.min.js"></script> -->
    <script src="./mqtt.min.js"></script>
    <script src="./webclient.js" charset="utf-8"></script>

引用完mqtt.min.js的脚本后,我们就可以在javascript脚本里使用mqtt脚本的方法了。
注意,脚本第一行的mqtt.connect函数里填写的url可以是多种形式的,这里推荐ws://协议的形式,当然也可以是mqtt://192.168.3.113:8888,但如果是大家用的也是mqtt@4.2.8版本的,就会报错。这个错是官方的错,见该博客,其实修改成4.0.0版本的mqtt.min.js版本就不会有问题。其实不管什么url,连的其实还是websocket的端口。
在这里插入图片描述

webclient.js

const client = mqtt.connect('ws://192.168.3.113:8888', {
  username: "user",
  password: '123456'
});
// const client = mqtt.connect('mqtt://192.168.3.113:1883', {
//   username: "user",
//   password: '123456'
// });

client.subscribe("carinfo");
client.subscribe("steerbutton");

client.on("connect", function () {
  console.log("服务器连接成功");
  console.log(client.options.clientId);
  client.subscribe("carinfo", { qos: 1 }); // 订阅text消息
});

client.on("message", function (top, message) {
   console.log("当前topic:", top);
   console.log(message.toString());
  let messagestring=message.toString();
  let stringafersplit=messagestring.split(",");
  let throttle=stringafersplit[0];
  let brake=stringafersplit[1];
  let steer=stringafersplit[2];
  let rotationspeed=stringafersplit[3]
  let SOC=stringafersplit[4]
  document.getElementById('throttle').innerHTML = throttle + '%';
  document.getElementById('brake').innerHTML =  brake + '%';
  document.getElementById('steer').innerHTML = steer + "°";
  document.getElementById('rotationspeed').innerHTML = rotationspeed + "rpm";
  document.getElementById('SOC').innerHTML=SOC+'%';
});

// setInterval(() => {
//     steer = steer + 1;
//     document.getElementById('throttle').innerHTML = throttle + '%';
//     document.getElementById('brake').innerHTML = brake + '%';
//     document.getElementById('steer').innerHTML = steer + "°";
// }, 10)

源码如上,先连上broker,然后订阅carinfo这个话题,在message的事件中,我们利用DOM对html中的内容进行赋值DOM教程

测试

我们先用MQTTBox工具进行测试,首先在终端开启服务器。
在这里插入图片描述
可以看到,三个端口都在正常监听的状态。然后我们在浏览器中访问,192.168.3.113:5000这个地址,当然任何连如同一个网络的电脑和手机都可以访问。网页如下。
在这里插入图片描述

再打开MQTTBox。配置如下。
在这里插入图片描述
此时可以在服务器的终端看到,两个mqtt客户端已经连上了broker。
在这里插入图片描述
这里我们通过MQTTBox,发布carinfo话题,payload随便填一些信息,点击publish.在这里插入图片描述
网页端可以看到,我们发送的信息已经在网页端更新了。
在这里插入图片描述
到此为止我们已经完成了后端和前端的代码,只剩下嵌入式设备的接入了。源码链接

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2021-08-21 15:38:02  更:2021-08-21 15:39:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/28 17:50:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计