我一个学软件的小白想要找一个最简单的物联网案例跟着做,一直没找到。最后摸索了一番打算自己写一篇。关于细学物联网可以看太极创客,但还是要提一句,官方文档总是比大多数博客有用的。

基本框架

mqtt服务器作为消息中转,uni-app(vue)通过mqtt协议连接服务器,另一端esp01s也连接mqtt服务器,然后就可以进行数据传输。
这种通信方式主要用于控制指令的传输和实时数据显示,例如传感器数据可以通过mqtt直接显示到前端,但持久化需要搭建后端与mqtt服务器连接再将消息存到数据库,mqtt服务器不提供持久化服务。

为什么使用MQTT

mqtt协议是应用层协议,依然是基于TCP/IP的。

mqtt服务器的基本工作原理就是消息的订阅与发布,mqtt服务器被称为服务端,其他的设备连接到该服务器被称为客户端。在这里我们的uni-app前端和 esp01s在连接到服务器以后都被称为客户端。
客户端与客户端之间的消息传输靠的是订阅同一个主题,这个主题就类似于一个qq群,订阅就相当于加入这个群,发布就相当于在这个群里发消息,所以只要是订阅了同一个主题就能收到其他设备在该主题下发布的消息。当然一个设备可以订阅多个主题,一般是手机前端订阅多个设备的信息。主题的名字是自己取的,只要有人订阅了这个名字,这个主题就存在了。

如果订阅主题的设备意外断线了,mqtt服务器会将其他设备发布的数据保存在服务端,当该设备重新连上服务器后会继续将数据发送给该设备,相当于你上线看到群历史记录一样。
所以,
这可以很大程度保证在网络较差的环境下数据的稳定送达,并且两个客户端并不是必须要同时在线交流,相当于发微信一样发完可以继续干自己的事。非常适合物联网设备的数据通信。

战前准备

必要硬件:esp01s、配套继电器。
可选硬件:灯、电池、杜邦线。(如果你自己有电源、导线或者PCB板、目标设备)
工具:很小的一字螺丝刀(用于拧松继电器上的接线口螺丝)

esp01s

esp01s是esp8266系列wifi模块的一种,芯片与系列中其他型号相同,外部模块比较简约。
esp8266芯片源自于国内企业乐鑫科技,推荐从乐鑫旗下或者安信可旗下购买。

其他设备

要让模块在通电的时候做我们希望让它做的事需要对其进行编程,所以需要一个烧录器。

配套继电器

电池(电压需要大于继电器的标准电压才能让它工作)

杜邦线(线两头有细金属插头接口,分公母,其实在找到这线之前我甚至不知道这线叫什么名字)

LED灯(本来我搜的是发光二极管,不过这个引脚看着蛮舒服的,可以直接插杜邦线)

操作思路

  1. 安装EMQX(mqtt服务器)和MQTT X(mqtt电脑客户端)
  2. 安装Hbuilder,创建uni-app项目(使用Vue框架的)
  3. Vue连接EMQX
  4. 安装Arduino(用于编写硬件的编辑器)
  5. esp01s连接EMQX
  6. 连接硬件测试

安装EMQX、MQTT X

EMQX是一个mqtt服务器,你可以把它安装到本地linux系统上运行,但是我估计大部分人用的是windows,并且没有其他闲置的linux,除非你买个云服务器。
所以他们非常贴心的提供了免费的云EMQX,你可以直接通过连接他们现成的服务器进行消息中转。
如果你打算下载到本地安装可以看官方文档:快速开始 | EMQX文档
我有一个树莓派所以我是安装到了我的树莓派上。

MQTT X是一个可以直接在电脑上运行的客户端程序,可以用于测试发送和接收mqtt消息。
官网地址:MQTT X:优雅的跨平台 MQTT 5.0 桌面客户端工具

使用本地EMQX

EMQX文档中提到过Dashboard这个系统提供的可视化操作界面。服务器在运行以后默认自动启动Dashboard。
我们可以通过设备IP地址加18083访问到这个操作界面,用户名默认admin,密码默认public。
默认英文,可以在设置里转中文。
工具里的Websocket界面会默认显示你的服务器地址(192.168.1.109是我的树莓派地址)
不过是ws开头的 ws://192.168.1.109:8083/mqtt
如果是mqtt开头是 mqtt://192.168.1.109:1883
除了我的IP地址其他都是系统默认。

使用MQTT X

官方文档会引导你创建一个新的连接。就是点击侧边栏第二个加号,然后它默认显示的服务器地址就是他们官方提供的免费线上服务器。
名称自己填着能认就行。
Client ID用于让服务器识别你这个客户端的,这里随机生成的,不用管。
地址头有mqtt和ws两种,mqtts和wss是加密传输。(部分前端比如微信小程序官方要求加密传输所以必须要加s才行,但是官方提供的免费服务器只提供非加密传输,所以用微信小程序的建议自己搭服务器。)
用户名和密码暂时不填,会默认免密登录服务器,之后有实际需要再说。

我这里名称为remote_test的连接了免费远程服务器。然后点击添加订阅就可以添加订阅。

建议不要订阅默认的testtopic/#主题名,因为用的人很多,别人在这里发的内容你都会接收到,不适合我们自己测试。

是不是特别像一个聊天室…testtopic/后面跟#意思是只要是testtopic/开头的都可以被接收到。
#只会用于订阅的时候,发布时必须指明你发布到哪一个主题,不能是范围,比如我写的这个testtopic/down是要发布到的主题。
下面的Json格式数据是要发送的内容,Payload中可以选择数据格式,我用的是Json。
Qos是发送后对方如果无响应的重发策略,暂时不用管。

安装Hbuilder

使用uni-app是因为它可以直接跑在手机上,毕竟一般控制开关都是用手机的。
使用Hbuilder是因为可以快速生成一个uni-app项目,要真作为一个编辑器感觉不如VScode。

Hbuilder官网:HbuilderX-高效极客技巧
创建uni-app项目可以看官方文档的快速开始:uni-app官网

Vue连接mqtt服务器

需要先在Hbuilder底部的终端引入mqtt。目前已经有4.0.0版本,但是可能有小问题。

npm install mqtt@3.0.0

在这里我就只放一下js部分的连接脚本。
前端界面样式,发布和接收数据之后的逻辑你们可以自己设计。
这里我的state变量来自vuex。
与硬件端的代码有一些对应的地方,建议放在一起看。

<script scoped>export default {data() {return {//mqttHost: "192.168.1.109"  // 自己的服务器地址mqttHost: "broker.emqx.io", // 官方服务器地址mqttPort: 8083,mqttPath: "/mqtt",client: {}  // 代表我的客户端}},onLoad() {},// 注意在OnShow()中连接onShow() {this.mqttConnect()},methods: {mqttConnect() {var that = this// 连接服务器// 在其他地方你可能会看到引入connect的方式,但是那样在APP端可能无法连接服务器var mqtt = require('mqtt/dist/mqtt.js')// #ifdef APP-PLUSvar pinf = plus.push.getClientInfo(); // 获取终端标识var clientId = pinf.clientid; //客户端标识const options = {port: that.mqttPort,clientId,};that.client = mqtt.connect("wx://" + that.mqttHost + that.mqttPath, options);//#endif// #ifdef H5const options = {port: that.mqttPort,};that.client = mqtt.connect("ws://" + that.mqttHost + that.mqttPath, options);//#endif// 如果连接成功执行函数that.client.on('connect', function(){console.log('connected')// 订阅主题并执行函数that.client.subscribe('testtopic/up/#', function(err){if(!err){console.log('get topic')}})})// 我设定设备会每隔一段时间发布一次自己的状态// 如果监听到主题执行函数that.client.on('message', function(topic,message){console.log(topic)// 我设计的主题末尾是设备的mac地址,这里是将mac地址赋值给idlet id = ''id = topic.substr(topic.lastIndexOf("/") + 1)let data = {}data = JSON.parse(message)let set = {"id": id,"state": data.state}// 将前端该id的设备状态设为获取到的状态that.$store.dispatch('setState', set)  })},// 点击灯的开关按钮clickButton(item) {var that = this// 如果此时是开着的(state为true)if(item.state){// 发布关闭消息that.client.publish('testtopic/down/'+item.id,'{"switch": 0}',function(err){if(!err){console.log(item.name+' off')let set = {"id": item.id,"state": false}// 由于我设定设备会间隔一段时间发布一遍状态// 那么我们点击以后前端按钮不一定马上会做出反应// 所以我们不应该等待设备发状态再更改前端按钮的状态// 应该直接前端先改了,如果设备改状态失败,再通过设备发布的状态改回去that.$store.dispatch('setState', set)}})}else{// 发布开启消息that.client.publish('testtopic/down/'+item.id,'{"switch": 1}',function(err){if(!err){console.log(item.name+' on')let set = {"id": item.id,"state": true}that.$store.dispatch('setState', set)}})}},}}
</script>

安装Arduino

用于编写c语言硬件程序的编辑器,配合烧录器将程序传入硬件。
下载地址:Software | Arduino

基本配置

打开 文件 > 首选项

像这种项目文件不建议放c盘。
输出模式为编译。
管理器网址直接填这个
http://arduino.esp8266.com/stable/package_esp8266com_index.json
确认后关了重启。

esp8266开发板配置

打开 工具 > 开发板 > 开发板管理器…

搜索esp8266并安装。

选择开发板:NodeMCU 1.0,与esp01s通用。

ESP01s连接mqtt服务器

我是看这个了解了大概框架再改的:太极创客 | MQTT基础篇

Arduino引入mqtt相关库

使用mqtt需要先引入它的包。
打开 工具 > 管理库

搜索PubSubClient,可能需要往下翻一下。

Arduino引入Json操作相关库

由于我是以Json格式的数据发布的,所以在esp01s接收到以后需要会处理Json数据。

Aduino源码

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <Ticker.h>
#include <ArduinoJson.h>// 设置wifi接入信息(请根据您的WiFi信息进行修改)
const char* ssid = "This is not 516";
const char* password = "zz888666";
const char* mqttServer = "192.168.1.109";  //可替换官方提供的域名:broker.emqx.io
// 如以上MQTT服务器无法正常连接,请前往以下页面寻找解决方案
// http://www.taichi-maker.com/public-mqtt-broker/Ticker ticker;
WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);int count;    // Ticker计数用变量
int pin = 0;  // 设置一个变量代表控制继电器开关的GPIO// 通电初始化函数
void setup() {Serial.begin(9600);  // 波特率//pinMode(LED_BUILTIN, OUTPUT);  // 这里换成变量pinMode(pin, OUTPUT); digitalWrite(pin, LOW);  // GPIO0 低电平,吸合继电器,作为初始状态// Ticker定时对象ticker.attach(1, tickerCount);//设置ESP8266工作模式为无线终端模式WiFi.mode(WIFI_STA);// 连接WiFiconnectWifi();// 设置MQTT服务器和端口号mqttClient.setServer(mqttServer, 1883);mqttClient.setCallback(receiveCallback);// 连接MQTT服务器connectMQTTServer();
}// 状态持续函数,一直重复执行
void loop() {if (mqttClient.connected()) { // 如果开发板成功连接服务器// 每隔3秒钟发布一次信息,一般用于状态报告if (count >= 3){pubMQTTmsg();count = 0;}    // 保持心跳mqttClient.loop();} else {                  // 如果开发板未能成功连接服务器connectMQTTServer();    // 则尝试连接服务器}
}void tickerCount(){count++;
}// 连接MQTT服务器
void connectMQTTServer(){// 根据ESP8266的MAC地址生成客户端ID(避免与其它ESP8266的客户端ID重名)String clientId = "esp8266-" + WiFi.macAddress();// 连接MQTT服务器if (mqttClient.connect(clientId.c_str())) { Serial.println("MQTT Server Connected.");Serial.print("Server Address: ");Serial.println(mqttServer);Serial.print("ClientId: ");Serial.println(clientId);subscribeTopic(); // 订阅指定主题} else {Serial.print("MQTT Server Connect Failed. Client State:");Serial.println(mqttClient.state());delay(3000);}
}// 发布信息
void pubMQTTmsg(){// 建立发布主题。String topicString = "testtopic/up/"+WiFi.macAddress();  // 上行主题,设备到控制端char publishTopic[topicString.length() + 1];  strcpy(publishTopic, topicString.c_str());// 定时向服务器主题发布当前GPIO0引脚状态String state;if(digitalRead(0)){state = "{\"state\": false}";  // 高电平断开继电器} else {state = "{\"state\": true}";  // 低电平吸合继电器}// 打包为JSON,但是我发现message变成了null,所以放弃了,直接上面写JSON...
//  DynamicJsonDocument doc(1024);
//  JsonObject obj = doc.as<JsonObject>();
//  obj["state"] = state;
//  String message;
//  serializeJson(doc, message);char publishMsg[state.length() + 1];   strcpy(publishMsg, state.c_str());// 实现ESP8266向主题发布信息if(mqttClient.publish(publishTopic, publishMsg)){Serial.print("Publish Topic: ");Serial.println(publishTopic);Serial.print("Publish message: ");Serial.println(publishMsg);    } else {Serial.println("Message Publish Failed."); }
}// 订阅指定主题
void subscribeTopic(){// 建立订阅主题。String topicString = "testtopic/down/"+WiFi.macAddress();  // 下行主题,控制端到设备char subTopic[topicString.length() + 1];  strcpy(subTopic, topicString.c_str());// 通过串口监视器输出是否成功订阅主题以及订阅的主题名称if(mqttClient.subscribe(subTopic)){Serial.print("Subscribe Topic: ");Serial.println(subTopic);} else {Serial.print("Subscribe Fail...");}
}// 收到信息后的回调函数
void receiveCallback(char* topic, byte* payload, unsigned int length) {Serial.print("Message Received [");Serial.print(topic);Serial.println("] ");// 将获取到的pyte类payload消息转换为String类型的dataString data = "";for (int i = 0; i < length; i++) {data = data + (char)payload[i];}Serial.println(data);// 一般我们会发布JSON格式的消息,所以就需要解析获取JSON中的数据// 声明你的json数据中存在几个对象,如果有list列表,需要+ JSON_ARRAY_SIZE(1),这里我的json只有{"switch":1}const size_t capacity = JSON_OBJECT_SIZE(1) + 60;  StaticJsonDocument<capacity> jsonBuffer;// Parse JSON object解析 JSONdeserializeJson(jsonBuffer, data);JsonObject object = jsonBuffer.as<JsonObject>();Serial.println(object["switch"].as<String>());
//  Serial.println("");
//  Serial.print("Message Length(Bytes) ");
//  Serial.println(length);if (object["switch"].as<String>() == "1") {     // 如果收到的信息为"1",注意双引号为String,单引号为char//digitalWrite(LED_BUILTIN, LOW);  // 则点亮LED。digitalWrite(pin, LOW);  // GPIO0 低电平,吸合继电器} else {                           //digitalWrite(LED_BUILTIN, HIGH); // 否则熄灭LED。digitalWrite(pin, HIGH); // GPIO0 高电平,断开继电器}
}// ESP8266连接wifi
void connectWifi(){WiFi.begin(ssid, password);//等待WiFi连接,成功连接后输出成功信息while (WiFi.status() != WL_CONNECTED) {delay(1000);Serial.print(".");}Serial.println("");Serial.println("WiFi Connected!");  Serial.println("");
}

上传到硬件

这个时候你需要将esp01s插在烧录器上,再把烧录器插到电脑上。
查看你的串口是否识别到。

如果有就可以点击左上角箭头上传到硬件。

源码中的println函数会将数据输出到串口监视器。

上传成功后就会开始println输出,并且发布自己开关的状态到mqtt服务器。

此时你可以在客户端看到硬件发布的内容。

然后你可以测试用客户端发送关闭消息。此时它定时发布的GPIO 0引脚就变成高电平。

硬件演示

把esp01s插到继电器上就能用来控制开合了。

继电器背面标了接口符号。VCC:电源,GND:接地。
GPIO 0为低电平时(开):COM与NO闭合。
GPIO 0为高电平时(关):COM与NC闭合。

然后我另外从电池接了线出来给LED灯供电来模拟开关灯。

关于mqtt主题

可能会有人和我一样奇怪为什么上行下行的数据要用两个主题,不是一个主题两边都能发数据吗。
于是我自己试了一下发布和订阅同一个主题,在MQTT X客户端上我们可以看到如果在自己已经订阅的主题中发布信息,会同时在该主题中收到自己发布的信息。
那么如果两边用同一个主题交换消息,两边就都需要识别每一个消息是对方发的还是自己发的,识别方法可能就是在Payload中多写一个数据标识是谁发的。这明显会增加很多的判断成本。
按照这样一个思路,一个主题最好的使用方法应该是一个发布者对应多个订阅者或者一个订阅者对应多个发布者。
但是同为客户端,也分为手机控制端和物联网IoT设备。
那么在不考虑IoT设备之间互相订阅的前提下,一个IoT设备,应该都会有一个主题是自己独占用来发布的,多个控制端可以订阅这个主题,同时有一个主题是独占用来接收控制信息的,多个控制端可以发布信息到这个主题。而一个控制端,与每一个IoT设备之间都会有一个发布主题和订阅主题,不存在自己独占的发布或订阅主题。

ESP01s + MQTT + uni-app(Vue) 入门物联网继电器开关实践相关推荐

  1. vue插槽solt ,uni.app

    一.什么是插槽? 插槽就是子组件提供给父组件使用的一个占位符,用<slot></solt>表示父组件可以在这个占位符中填充任何模板代码. 二.插槽的用法 1.创建一个子组件,在 ...

  2. vue入门项目:类新闻类移动端app

    vue入门项目:类新闻类移动端app 工程地址 github地址 项目介绍 使用框架 项目是一个使用vue脚手架开发的类新闻类应用 需要知识: vue vue-router axios mui min ...

  3. 5G 时代的 Android App 开发入门与项目实战

    随着移动互联网的持续发展,Android系统从智能手机逐步拓展到平板电脑.智能电视.车载大屏.智能家居.智能手表等诸多设备,Android开发依然是前景可期的IT岗位. 当然,整个社会正在迈向5G时代 ...

  4. uni app 调用网络打印机_uni-app 的使用体验总结

    [实践] uni-app 的使用总结 最近使用 uni-app 的感受. 使用体验 没用之前以为真和 Vue 一样,用了之后才知道.有点类似 Vue 和 小程序结合的感觉.写类似小程序的标签,有着小程 ...

  5. 建立项目接口文档_分享:一步一个脚印,vue入门之使用mockjs搭建vue项目测试服务器...

    在以前的文档中,我们构建了vue项目的整体架构,详见vue入门:vue项目架构设计起步,现在我们主要对其中的mock server 进行完善. 一.概述 前后端分离的项目优点之一就是可以前后端并行开发 ...

  6. Vue入门指南-05 Vue实例的生命周期(快速上手vue)

    生命周期钩子 = 生命周期函数 = 生命周期事件 实例创建期间的生命周期函数 // 刚初始化了一个空的实例对象, 这时候只有默认的一些生命周期函数和默认事件, 其他都未创建. // 如果要调用 met ...

  7. 前端开发~uni-app ·[项目-仿糗事百科] 学习笔记 ·004【App.vue引入全局公共样式】

    注:前言.目录见 https://god-excious.blog.csdn.net/article/details/105312456 文章目录 [009]引入官方CSS样式库 [010]引入第三方 ...

  8. uni app 零基础小白到项目实战-1

    uni-app是一个使用vue.js开发跨平台应用的前端框架.开发者通过编写vue.js代码,uni-app将其编译到Ios,android,微信小程序等多个平台,保证其正确并达到优秀体验.Uni-a ...

  9. uni app 自动化索引列表

    uni app 自动化索引列表,官方推荐的第三方插件 https://ext.dcloud.net.cn/plugin?id=375 [{"letter": "A&quo ...

最新文章

  1. 希捷+ 加了些什么?
  2. Python简介及安装
  3. 对象的引用和clone
  4. phpmyadmin #1045 - Access denied for user 'root'@'localhost' (using password: NO)
  5. 小红书笔记_小红书的沙雕笔记,害人不浅啊
  6. 数仓dw怎么建_从0建设离线数据仓库
  7. linux怎么安装ros系统,ubuntu14.04安装ROS indigo的详细图解步骤
  8. ubuntu 查找opencv安装路径_Ubuntu系统---配置OpenCV
  9. 士林变频器面板如何调速度_必读干货丨西威变频器DRIVE OVERLOAD故障处理
  10. 凸优化第四章凸优化问题 4.7向量优化
  11. 用nginx部署前端项目
  12. Web前端_项目实践02_ins北欧风多肉植本店主网页(纯HTML+CSS静态页面)
  13. 如何写会议 Rebuttal
  14. IPFS节点对外入口
  15. Windows ❀ Windows系统下端口连通性常见的验证方法
  16. 【调剂】西北师范大学计算机科学与工程学院 2023年硕士研究生调剂公告
  17. 特殊矩阵的压缩存储(对称矩阵,三角矩阵,对角矩阵,稀疏矩阵的顺序,链序存储,十字链表的建立)
  18. 口径、维度、指标和字段
  19. 程序员修炼之道---之小工到专家
  20. 蓝桥杯国赛06——第十届国赛客观题

热门文章

  1. 【思维 构造】CodeForces - 148C Terse princess
  2. 趣学算法之分枝限界法
  3. 基于B2C的网上拍卖系统—秒杀与竞价(附论文)
  4. HTML CSS JS电影网页设计 DW个人网页制作 Hbuilder制作简单的电影网页 在线电影网页设计与制作 web前端大作业
  5. ios 照片添加水印
  6. 10KW科士达UPS电源PCB原理图10KWUPS方案 10KW科士达,UPS电源 包括PCB, 原理图,源代码。
  7. 激进推动2G退网迎恶果,中国联通用户数再跌,快跌穿3亿了
  8. Mac office2019
  9. cdr怎么转换成psd转换为位图标准_如何将CorelDRAW中矢量图形转换为位图
  10. Java动态规划算法从入门的到熟练