系统框架分为:感知层,传输层,应用层
硬件:MCU(STC89C52/STM32)及USB线、esp8266-01s(wifi模块),温湿度传感器(DHT11),CH340模块(板载)
软件:emqx、keil、cubemax,串口调试助手,ISP下载工具,微信小程序开发者,
链接地址:https://mqttx.app/zh
DHT11引脚
接线:
1VCC --- 外接3.3V-5V
2GND--- 外接GND
3DATA --- 接单片机O口(51单片机IO口,STM32开发板接PG11)
DHT11数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。该传感器包括一个电容式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连。
DHT11工作时序
Esp8266(NodeMCU)是一款集成了Wifi功能的MCU开发板,可以直接连接wifi,开发环境多元化,也是表较受欢迎的物联网芯片。
ESP8266是一款高性能的WIFI串口模块,内部集成MCU能实现单片机之间串口通信,是目前使用最广泛的一种WIFI模块之一。可以简单理解为一个WIFI转串口的设备,不用知道太多WIFI相关知识,只需要知道串口怎么使用就可以。
1、AT指令开发,开发简单,只需知道AT指令集,以及它的通信方式即可,但是需要MCU与其通信,不能独立完成某项功能,烧录过程相对与其它开发方式来说比较麻烦。 2、使用lua脚本进行开发,NodeMCU本质也是ESP8266,只是它的固件是与lua脚本语言交互,可以节省资源,开发简单,代码量少,但是lua解释器执行效率较低。 3、Arduino IDE开发,使用C语言进行编程,集编程和烧录一体,并且还有许多的库函数可以使用。Arduino IDE相对lua需要写的带代码较长。如果要查看底层的代码,表较麻烦,不容易查看。 4、VS Code 配置Arduino开发环境,可以在VS Code 进行编程和烧录,使用快捷键一键烧录,使用方便,并且还自带代码补全功能,还可以很方便的查看底层原代码,推荐使用这种方式。
ESP8266系列一般具有两种开发方式:AT指令开发和SDK开发。
AT指令:厂家出厂时预先在ESP8266芯片烧入好固件,封装好WiFi的协议栈,内部已经实现透传,而用户只需要使用一个USB转TTL的模块或者单片机的串口就能实现与WiFi模块的通信,发送AT指令来对WiFi模块进行控制。(和蓝牙透传模块类似)
SDK开发:由于ESP8266本身即是可编程的芯片,可以把它视为一个带有无线通信的单片机,而用户需要在专门的IDE中编写对应的程序,然后通过烧写固件的方式将程序写入到芯片中,因此,想要实现WiFi通信,需要自定义WiFi协议栈,对用户掌握的相关知识要求更高。
AT指令类型:
AT测试指令:AT
AT配置指令:AT+cmd=<值>
AT查询指令:AT+cmd?
注:需要模块升级
TXD-U --- RXD
RXD-U --- TXD
GND --- IO0 --升级的时候需要连接
5V --- 3V3
GND --- GND
x1恢复出厂设置 AT+RESTORE
2测试模块 AT
3关闭回显 ATE0
4查看版本信息AT+GMR
5复位模块状态 AT+RST
6设置客户端模式
7AT+CWMODE=1 客服端 Station
8AT+CWMODE=2 服务端 AP
9AT+CWMODE=3 双端模式
10查看附近无线网络 AT+CWLAP
11
12连接WIFI AP
13AT+CWJAP="wifi名","密码"
14获取ip地址 AT+CIFSR
15
16查询网络连接状态 AT+CIPSTATUS
17开启传透模式 AT+CIPMODE=1
18关闭穿透模式 AT+CIPMODE=0
19
20AT+UART=9600,8,1,0,0 设置波特率
21
22UDP连接
23AT+CIPSTART="UDP","目标IP",目标端口号,本机端口号,0
24如:AT+CIPSTART="UDP","192.168.1.1",8080,9000,0
25
26TCP连接
27AT+CIPSTART="TCP","目标IP",目标端口号
28如:AT+CIPSTART="TCP","192.168.1.1",8080
29
30开启发送 AT+CIPSEND
31指定发送长度 AT+CIPSEND=num
32退出发送 +++
xxxxxxxxxx
141连接MQTT服务器服务器
21. AT 测试指令
32. AT+RST 复位
43. AT+CWMODE=1 客户端模式
54. AT+CWJAP="wifi名","密码"
6 eg.AT+CWJAP="iPhone13_yxq","15270910076"
75. AT+MQTTUSERCFG=0,1,"STC89C52","espressif","1234567890",0,0,"" MQTT配置信息
86. AT+MQTTCONN=0,"43.138.234.120",1883,0 连接MQTT服务器地址
97. AT+MQTTSUB=0,"/mcu/sub",1 订阅主题topic
108. AT+MQTTPUB=0,"/mcu/pub","\{\"beep\":0\}",1,0 推送主题topic
11
12接收到订阅的topic
13+MQTTSUBRECV:0,"/mcu/sub",26,{"target":"led","value":1}
14接收到的标志,
xxxxxxxxxx
141连接服务器
21. AT+CWMODE=1 客服端
32. AT+CIPMODE=1 透传模式1
43. AT+CWJAP="wifi名","密码"
54. AT+CIFSR 获取ip地址
65. AT+CIPSTART="UDP","目标ip地址",目标端口,8266端口默认9000,0
7发送数据有两种方法
8一 1. AT+CIPSEND (开启传输数据)
92. > (这个符号代表等待输入,回车发送,在程序里用\r\n转义发送)
103. +++ (发送+++代表退出发送,串口助手里需要关闭发送新行才能关闭发送,程序里用+++\r\n关闭)
11二 1. AT+CIPSEND=num (指定发送数据长度,由于指定长度,达到长度后会自动发送,并退出发送)
122. > (这个符号代表等待输入,回车发送,在程序里用\r\n转义发送)
13
14多次发送只需要循环发送数据方法
xxxxxxxxxx
121连接服务器
21. AT+CWMODE=1 客服端
32. AT+CIPMODE=0 透传模式0
43. AT+CWJAP="wifi名","密码"
54. AT+CIFSR 获取ip地址
65. AT+CIPSTART="TCP","目标ip地址",目标端口
7发送数据有两种方法
8一 1. AT+CIPSEND (开启传输数据)
9 2. > (这个符号代表等待输入,回车发送,在程序里用\r\n转义发送)
10 3. +++ (发送+++代表退出发送,串口助手里需要关闭发送新行才能关闭发送,程序里用+++\r\n关闭)
11二 1. AT+CIPSEND=num (指定发送数据长度,由于指定长度,达到长度后会自动发送,并退出发送)
12 2. > (这个符号代表等待输入,回车发送,在程序里用\r\n转义发送)
总结:上面讲的都是AT指令,真正应用都要在STC89C51中,STC89C51连接ESP8266也是使用串口发送AT指令,与串口助手用法是一样的。
具体实现看下面代码
STC89C516通过串口发送AT指令需要在最后加"\r\n"(0x0D 0x0A)作为回车
xxxxxxxxxx
1611、升级固件,升级到MQTT库文件
22、修改默认波特率115200,修改成9600,51单片只能配置成9600
33、按照MQTT连接方式进行连接
4 AT 测试指令
5 AT+RST 复位
6 AT+CWMODE=1 客户端模式
7 AT+CWJAP="wifi名","密码"
8 eg.AT+CWJAP="iPhone13_yxq","15270910076"
9 AT+MQTTUSERCFG=0,1,"STC89C52","espressif","1234567890",0,0,"" MQTT配置信息
10 AT+MQTTCONN=0,"43.138.234.120",1883,0 连接MQTT服务器地址
11 AT+MQTTSUB=0,"/mcu/sub",1 订阅主题topic
12 AT+MQTTPUB=0,"/mcu/pub","\{\"beep\":0\}",1,0 推送主题topic
134、emqx软件测试
14链接地址:https://mqttx.app/zh
15 上行数据和下行数据的测试
16 Topic
概念:MQTT(Message Queuing Telemetry Transport,消息队列遥测传输协议),是一种基于发布/订阅(publish/subscribe)模式的“轻量级”通讯协议,该协议构建于TCP/IP协议上,由IBM在1999年发布。MQTT最大优点在于,可以以极少的代码和有限的带宽,为连接远程设备提供实时可靠的消息服务。做为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用。
特点: MQTT协议运行在TCP/IP或其他网络协议,提供有序、无损、双向连接。其特点包括:
使用的发布/订阅消息模式,它提供了一对多消息分发,以实现与应用程序的解耦。
对负载内容屏蔽的消息传输机制。
对传输消息有三种服务质量(QoS):
最多一次,这一级别会发生消息丢失或重复,消息发布依赖于底层TCP/IP网络。即:<=1。
最少一次,这一级别会确保消息到达,但消息可能会重复。即:>=1。
只有一次,确保消息只有一次到达。即:=1。在一些要求比较严格的计费系统中,可以使用此级别。
数据传输和协议交换的最小化(协议头部只有2字节),以减少网络流量。
通知机制,异常中断时通知传输双方。
(1)MQTT实现方式
实现MQTT协议需要:客户端和服务器端 MQTT协议中有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。 MQTT传输的消息分为:主题(Topic)和负载(payload)两部分 Topic,可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容(payload) payload,可以理解为消息的内容,是指订阅者具体要使用的内容
3.MQTT
客户端一个使用MQTT
协议的应用程序或者设备,它总是建立到服务器的网络连接。客户端可以:
发布其他客户端可能会订阅的信息
订阅其它客户端发布的消息
退订或删除应用程序的消息
断开与服务器连接
MQTT
服务器MQTT
服务器以称为“消息代理”(Broker),可以是一个应用程序或一台设备。它是位于消息发布者
和订阅者
之间,它可以:
接受来自客户的网络连接
接受客户发布的应用信息
处理来自客户端的订阅和退订请求
向订阅的客户转发应用程序消息
(1)搭建框图
搭建之前需要在腾讯云服务器上购买一个自己的云服务器(华为云、阿里云、腾讯云、移动云)
(2)当前主流的MQTT服务器代理
Mosquitto:https://mosquitto.org/
VerneMQ:https://vernemq.com/
EMQX:https://www.emqx.io/(本次采用)
(3)云服务器安装EMQX
点击网址连接进入到首页
点击网页左下角切换成中文。
点击立即下载,选择Linux操作系统。
下载安装MQTT,在云服务器中安装后,启动EMQX。
xxxxxxxxxx
1211、配置 EMQX Yum 源
2
3curl -s https://assets.emqx.com/scripts/install-emqx-rpm.sh | sudo bash
4
52、安装 EMQX
6
7sudo yum install emqx -y
8
93、启动 EMQX
10
11 sudo systemctl start emqx
12
进入到安全中心,放开端口,增加防火墙放开端口。
(注:每个云服务商不一样,详细见云服务器控制台)
腾讯云服务器如下:
放开以下端口:
EMQX管理界面:18083
ssl:8883 --- 加密通道
Tcp:1883 -- 未加密通道
ws:8083 ---微信小程序
wss:8084 ---微信小程序加密通道
登录地址:云服务器IP地址:端口号
eg:127.0.0.1:18083
腾讯云服务器地址:http://43.138.234.120:18083/
默认账号密码:admin /public
修改成中文
MQTT服务器测试
连接服务器
订阅默认消息,同时发布消息,显示已接收和已发布则代表测试成功如下图。
MQTTX
下载方式
链接地址:https://mqttx.app/
MQTTX软件MQTT协议主题发布/订阅测试
发布主题:/my/sub
订阅主题:/my/Pub
(1)打开软件
(2)订阅主题
向该主题/my/sub发送消息
发送消息hello world情况
注册链接地址:https://mp.weixin.qq.com/
点击 “立即注册” 按钮进行注册(右上角)。注册的账号类型可以是订阅号、服务号、小程序以及企业微信,我们选择 “小程序” 即可。
填写注册信息
接着填写账号信息,需要注意的是,填写的邮箱必须是未被微信公众平台注册、未被个人微信号绑定的邮箱,而且每个邮箱仅能申请一个小程序。
激活邮箱之后,选择主体类型为 “个人类型”,并按要求登记主体信息,主体信息提交后不可修改。
1)新建项目
2)微信小程序页面介绍
3)项目的组成
4)页面信息
5)新建页面信息组成
xxxxxxxxxx
51###页面文件具体作用
2index.js 业务逻辑
3index.json 页面配置
4index.wxml 模板文件
5index.wxss 样式
激活邮箱
1)小程序的模板语法约等于vue的模板语法
xxxxxxxxxx
2411文本渲染
2{{ msg }}可以执行简单的js表达式
3{{2+3}}
4{{msg.length}}
5
62条件渲染
7wx:if=""
8wx:elif=""
9wx:else
10
113列表渲染
12wx:for="{{list}}"
13wx:key="index"
14{{item}}
15{{index}}
16
174自定义列表渲染
18定义item与index的名称
19wx:for="{{list}}}"
20wx:for-item="myitem"
21wx:for-index="myidx"
22{{myidx}}
23{{myitem}}
24
2)导入文件
xxxxxxxxxx
21import { 对象 } from "module";
2import { connect } from "../../static/mqtt";
3)wxss
xxxxxxxxxx
31微信小程序默认单位是rpx,html默认单位为px
2750rpx 等于一个屏幕的宽
3375就是50%的宽
4)事件
xxxxxxxxxx
41bindInput 表单输入时
2bindconfirm 表单输入确认
3bindtap 点击时候
4bindchange 改变时
5)表单的绑定
xxxxxxxxxx
101.wxml文件
2<input value="{{s1}}" bindinput="inputHd">
3
4.js文件
5inputHd(e){
6 this.setData({s1:e.detail.value})
7}
8
9表单的值获取:e.detail.value
10
6)内置的api
xxxxxxxxxx
81#显示提示
2showToast
3
4#本地存储
5wx.setStorageSync(key,value)
6
7#本地取
8wx.request 网络请求
7)生命周期
xxxxxxxxxx
41onLoad 页面加载完毕
2onShow 页面显示调用
3onPullDownRefresh 下拉刷新
4onReachBottom 触底更新
xxxxxxxxxx
261内置标签:
2
3(1)view:视图容器,类似div,整体布局使用view搭建框架,原生小程序采用flex布局
4
5(2)image:图片标签 类似img src路径,可以相对../ 直接绝对 /项目根开始
6
7(3)text:文本标签 类似span 包裹文字
8
9页面增加数据
10Page({
11data: {
12client: null,//连接的客户端
13temp: 23,//温度
14humi: 30,//湿度
15led: 0,//大灯的状态
16beep: 0//蜂鸣器的状态
17},
18
19数据的赋值/绑定
20this.setData({
21//变量名:赋值内容
22client:connect('wxs://broker.emqx.io:8084/mqtt')
23
24})
25表单的值获取:
26event.detail.value
iconfont图标下载
阿里巴巴图标:https://www.iconfont.cn/
小程序标题
xxxxxxxxxx
81 "window": {
2 "navigationBarBackgroundColor": "#ffffff",
3 "navigationBarTextStyle": "black",
4 "navigationBarTitleText": "单片机智能家居",
5 "backgroundColor": "#eeeeee",
6 "backgroundTextStyle": "light",
7 "navigationStyle": "custom"
8 }
tabbar制作
xxxxxxxxxx
131 "tabBar": {
2 "list": [{
3 "pagePath": "pages/index/index",
4 "text": "",
5 "iconPath": "/image/home.png",
6 "selectedIconPath": "/image/home_active.png"
7 },{
8 "pagePath": "pages/logs/logs",
9 "text": "",
10 "iconPath": "/image/user.png",
11 "selectedIconPath": "/image/user_active.png"
12 }]
13 }
wxml文件
xxxxxxxxxx
131<view class="header-container">
2 <view class="header-title">
3 <view>空气质量-良</view>
4 <view>江西赣州</view>
5 </view>
6 <view class="header-air">
7 <view>60</view>
8 <view>晴</view>
9 </view>
10 <view class="header-ad">
11 <view>今天天气真好,适合远游!</view>
12 </view>
13 </view>
wxss文件
xxxxxxxxxx
441.page-container{
2 /* 外边距 */
3 margin: 32rpx;
4
5}
6
7.head-container{
8 /* 背景颜色 */
9 background-color: #44a9f0;
10 /* 圆角 */
11 border-radius: 32rpx;
12
13}
14
15.head-container .head-title{
16 display: flex;
17 /* 分布在两边 */
18 justify-content: space-between;
19 /* 字体颜色 */
20 color: white;
21 /* 内边距:上下,左右 */
22 padding: 32rpx 32rpx;
23}
24
25.head-container .head-data{
26 display: flex;
27 /* 分布在两边 */
28 justify-content: space-between;
29 /* 字体颜色 */
30 color: white;
31 /* 内边距:上下,左右 */
32 padding: 0rpx 32rpx;
33 /* 字体大小 */
34 font-size: 72rpx;
35
36}
37
38.head-container .head-advice{
39 /* 字体颜色 */
40 color: white;
41 /* 内边距:上下,左右 */
42 padding: 12rpx 32rpx;
43
44}
wxml文件
xxxxxxxxxx
221 <view class="data-container">
2 <!-- 温度 -->
3 <view class="data-card">
4 <view>
5 <image class="data-card-icon" src="/image/temp.png" mode="" />
6 </view>
7 <view>
8 <view class="data-card-title">温度</view>
9 <view class="data-card-data"> {{temp}}°</view>
10 </view>
11 </view>
12 <!-- 湿度 -->
13 <view class="data-card">
14 <view>
15 <image class="data-card-icon" src="/image/humi.png" mode="" />
16 </view>
17 <view>
18 <view class="data-card-title">湿度</view>
19 <view class="data-card-data"> {{humi}}°</view>
20 </view>
21 </view>
22 </view>
wxss样式
xxxxxxxxxx
341/* 数据样式 */
2.data-container {
3 background-color: burlywood;
4 margin-top: 32rpx;
5 /* 网格布局 */
6 display: grid;
7 justify-content: center;
8 /* 卡片宽度大小设置 */
9 grid-template-columns: repeat(auto-fill, 300rpx);
10 /* 卡片之间间隙 */
11 grid-gap: 18rpx;
12}
13
14.data-container .data-card{
15 background-color: #fff;
16 height: 150rpx;
17 box-shadow:#d6d6d6 0 0 8rpx;
18 border-radius: 32rpx;
19 display: flex;
20 justify-content: space-between;
21 padding: 16rpx 16rpx;
22}
23.data-container .data-card .data-card-icon{
24 height: 80rpx;
25 width: 80rpx;
26 margin-top: 32rpx;
27}
28
29.data-container .data-card .data-card-data{
30 font-size: 48rpx;
31 font-weight: bold;
32 margin-top: 32rpx;
33}
34
xxxxxxxxxx
301 <!-- 温度 -->
2 <view class="data-card">
3 <!-- 左 -->
4 <view>
5 <!-- icon图片 -->
6 <image class="data-card-icon" src="/image/temp.png" mode=""/>
7 </view>
8 <!-- 右 -->
9 <view>
10 <view class="data-card-title">温度</view>
11 <view class="data-card-value">{{temp}}℃</view>
12 </view>
13 </view>
14
15 /**
16 * 页面的初始数据
17 */
18 data: {
19 //定义一个MQTT客户端
20 client:null,
21
22 temp:30,//温度
23 humi:60,//湿度
24 led:1,//LED按钮
25 beep:0//蜂鸣器按钮
26
27 },
28
29 数据绑定与前端进行交互
30 定义变量:{{ }} -- 用两对花括号与数据进行绑定。
微信小程序的网络使用
MQTT包下载
https://www.emqx.com/zh/mqtt-client-sdk
下载MQTT包文件
下载地址:unpkg.com/mqtt/dist/mqtt.min.js
导入mqtt.js的包
xxxxxxxxxx
31//引入MQTT包文件
2import { } from "module";
3eg:import { connect } from "../../static/js/mqtt";
前提:需要导入mqtt包文件至微信小程序。
使用 EMQ X Cloud 提供的 免费公共 MQTT 服务器 作为本次测试的 MQTT 服务器地址,服务器接入信息如下:
Broker: broker.emqx.io
TCP Port: 1883
WebSocket 端口: 8083
SSL/TLS Port: 8883
WebSocket Secure 端口: 8084
Broker: www.mqttssl.icu
公网IP:43.138.234.120
TCP Port: 1883
WebSocket 端口: 8083
SSL/TLS Port: 8883
WebSocket Secure 端口: 8084
微信小程序使用 WebSocket 的方式连接到 MQTT 服务器,但连接的 URL 地址中请使用 wxs
协议名称,连接及初始化数据的关键代码:
xxxxxxxxxx
3711、给客户端赋值,给定MQTT服务器地址端口号
2 that.setData({
3 //43.138.234.120
4 //client: connect('wxs://broker.emqx.io:8084/mqtt')
5 client: connect('wxs://43.138.234.120:8084/mqtt')
6 })
7
82、连接回调函数
9 //连接回调函数
10 that.data.client.on('connect', function name(params) {
11 console.log('成功连接到MQTT服务器')
12 //弹出窗口
13 wx.showToast({
14 title: '连接成功',
15 icon: 'success',
16 mask: true
17 })
183、订阅主题
19 //订阅上行数据
20 that.data.client.subscribe(devicePubTopic, function name(err) {
21 if (!err) {
22 console.log("成功订阅上行数据:"+ devicePubTopic)
23 }
24 })
254、接收订阅的消息
26 that.data.client.on('message', function name(topic, message) {
27 console.log(topic)
28 console.log(message)
29 })
30 5、发布消息
31 that.data.client.publish(mpPubTopic, "open_led", function name(err) {
32 if (!err) {
33 console.log("成功下发一条指令:开灯")
34 }
35 }
36
37 )
xxxxxxxxxx
181/**
2 * 生命周期函数--监听页面显示
3 */
4 onShow: function () {
5 var that = this
6 //设置连接MQTT服务器的地址和端口号
7 that.setData({
8 client:connect('wxs://43.138.234.120:8084/mqtt')
9 })
10 //连接MQTT服务器
11 that.data.client.on('connect',function name(err) {
12 console.log('成功连接服务器')
13 //连接成功的弹窗
14 wx.showToast({
15 title: '成功连接服务器',
16
17 })
18 })
xxxxxxxxxx
81 //订阅主题
2 that.data.client.subscribe('/mcu/pub',function name(err) {
3 if(!err)
4 {
5 console.log('成功订阅主题:/mcu/pub')
6
7 }
8 })
xxxxxxxxxx
151 //接收订阅消息
2 that.data.client.on('message',function name(topic,message) {
3 console.log(topic)
4 //message是一个16进制流
5 console.log(message)
6 //把message转换成json
7 var recData = JSON.parse(message)
8 console.log(recData)
9 //设置接收的数据到前端
10 that.setData({
11 temp : recData.temp,
12 humi : recData.humi
13 })
14
15 })
xxxxxxxxxx
271 //开关状态,传递值
2 onledchange(event) {
3 const that = this
4 console.log(event.detail.value) //获取按键的值,true,false
5 const sw = event.detail.value
6 that.setData({
7 led: sw
8 })
9 //根据开关发送消息至设备
10 if (sw) {
11 that.data.client.publish(mpPubTopic, "open_led", function name(err) {
12 if (!err) {
13 console.log("成功下发一条指令:开灯")
14 }
15 }
16
17 )
18 } else {
19 that.data.client.publish(mpPubTopic, "close_led", function name(err) {
20 if (!err) {
21 console.log("成功下发一条指令:关灯")
22 }
23 }
24
25 )
26 }
27 },
xxxxxxxxxx
671<!-- index.html -->
2<view class="page-container">
3 <!-- 头部 -->
4 <view class="header-container">
5 <view class="header-title">
6 <view>空气质量-良</view>
7 <view>江西赣州</view>
8 </view>
9 <view class="header-air">
10 <view>60</view>
11 <view>晴</view>
12 </view>
13 <view class="header-ad">
14 <view>今天天气真好,适合远游!</view>
15 </view>
16 </view>
17 <!-- 数据 -->
18 <view class="data-container">
19 <!-- 温度 -->
20 <view class="data-card">
21 <view>
22 <image class="data-card-icon" src="/static/image/temp.png" mode="" />
23 </view>
24 <view>
25 <view class="data-card-title">温度</view>
26 <view class="data-card-data"> {{temp}}°</view>
27 </view>
28 </view>
29 <!-- 湿度 -->
30 <view class="data-card">
31 <view>
32 <image class="data-card-icon" src="/static/image/humi.png" mode="" />
33 </view>
34 <view >
35 <view class="data-card-title">湿度</view>
36 <view class="data-card-data"> {{humi}}%</view>
37 </view>
38 </view>
39 <!-- 蜂鸣器 -->
40 <view class="data-card">
41 <view>
42 <image class="data-card-icon" src="/static/image/beep.png" mode="" />
43 </view>
44 <view >
45 <view class="data-card-title">蜂鸣器</view>
46 <view class="data-card-data">
47 <switch checked="{{beep}}" bindchange="onbeepchange" color="#2A69C7"/>
48 </view>
49 </view>
50 </view>
51 <!-- 灯 -->
52 <view class="data-card">
53 <view>
54 <image class="data-card-icon" src="/static/image/light.png" mode="" />
55 </view>
56 <view >
57 <view class="data-card-title">灯</view>
58 <view class="data-card-data">
59 <switch checked="{{led}}" bindchange="onledchange" color="#2A69C7"/>
60 </view>
61 </view>
62 </view>
63 </view>
64 <!-- 数据展示 -->
65 <view id = wx-echart class="echart-container">
66 </view>
67</view>
xxxxxxxxxx
601.page-container {
2 margin: 36rpx;
3}
4/* 头样式 */
5.header-container {
6 background-color: #2a69c7;
7 color: #fff;
8 border-radius: 24rpx;
9 padding: 40rpx 48rpx;
10}
11
12.header-container .header-air {
13 display: flex;
14 justify-content: space-between;
15 font-size: 64rpx;
16}
17
18.header-container .header-title {
19 display: flex;
20 justify-content: space-between;
21
22}
23
24.header-container .header-ad {
25 margin-top: 24rpx;
26 font-size: small;
27}
28/* 数据样式 */
29.data-container {
30 /* background-color: burlywood; */
31 margin-top: 32rpx;
32 display: grid;
33 justify-content: center;
34 /* grid-template-columns: auto auto; */
35 grid-template-columns: repeat(auto-fill, 300rpx);
36 grid-gap: 18rpx;
37
38}
39
40.data-container .data-card{
41 background-color: #fff;
42 height: 150rpx;
43 box-shadow:#d6d6d6 0 0 8rpx;
44 border-radius: 32rpx;
45 display: flex;
46 justify-content: space-between;
47 padding: 16rpx 16rpx;
48}
49.data-container .data-card .data-card-icon{
50 height: 72rpx;
51 width: 72rpx;
52 margin-top: 32rpx;
53}
54
55.data-container .data-card .data-card-data{
56 font-size: 48rpx;
57 font-weight: bold;
58 margin-top: 32rpx;
59}
60
xxxxxxxxxx
1411// index.js
2import {
3 echarts
4} from "../../static/js/echarts";
5
6const app = getApp()
7
8//引入MQTT包文件
9import {
10 connect
11} from "../../static/js/mqtt";
12
13const Host = 'broker.emqx.io' //mqtt服务器
14const Port = '8084' //mqtt服务器端口
15
16const deviceSubTopic = '/mcu/sub' //设备订阅Topic (小程序发布命令的Topic)
17const devicePubTopic = '/mcu/pub' //设备发布Topic (小程序订阅数据的Topic)
18
19const mpSubTopic = devicePubTopic
20const mpPubTopic = deviceSubTopic
21
22
23Page({
24 data: {
25 client: null,
26 temp: 23,
27 humi: 30,
28 led: 0,
29 beep: 0
30 },
31 //开关状态,传递值
32 onledchange(event) {
33 const that = this
34 console.log(event.detail.value) //获取按键的值,true,false
35 const sw = event.detail.value
36 that.setData({
37 led: sw
38 })
39 //根据开关发送消息至设备
40 if (sw) {
41 that.data.client.publish("/mcu/sub", "open_led", function name(err) {
42 if (!err) {
43 console.log("成功下发一条指令:开灯")
44 }
45 }
46
47 )
48 } else {
49 that.data.client.publish("/mcu/sub", "close_led", function name(err) {
50 if (!err) {
51 console.log("成功下发一条指令:关灯")
52 }
53 }
54
55 )
56 }
57 },
58
59 //蜂鸣器
60 //开关状态,传递值
61 onbeepchange(event) {
62 const that = this
63 console.log(event.detail.value) //获取按键的值,true,false
64 const sw = event.detail.value
65 that.setData({
66 beep: sw
67 })
68 //根据开关发送消息至设备
69 if (sw) {
70 that.data.client.publish("/mcu/sub", "open_beep", function name(err) {
71 if (!err) {
72 console.log("成功下发一条指令:开蜂鸣器")
73 }
74 }
75
76 )
77 } else {
78 that.data.client.publish("/mcu/sub","close_beep", function name(err) {
79 if (!err) {
80 console.log("成功下发一条指令:关蜂鸣器")
81 }
82 }
83
84 )
85 }
86 },
87
88
89 //事件函数
90 onShow() {
91 const that = this
92 //wxs 实际上就是wss => wss 实际上就是拥有SSL加密的web socket
93 that.setData({
94 // client: connect(`wxs://${Host}:${Port}/mqtt`)
95 client: connect('wxs://broker.emqx.io:8084/mqtt')
96 })
97
98 //连接回调函数
99 that.data.client.on('connect', function name(params) {
100 console.log('成功连接到MQTT服务器')
101 //弹出窗口
102 wx.showToast({
103 title: '连接成功',
104 icon: 'success',
105 mask: true
106 })
107 //订阅上行数据
108 that.data.client.subscribe('/mcu/pub', function name(err) {
109 if (!err) {
110 console.log("成功订阅上行数据:"+ devicePubTopic)
111 }
112 })
113 })
114
115 that.data.client.on('message', function name(topic, message) {
116 console.log(topic)
117 console.log(message)
118 //message 是16进制的buffer字节流
119 let dataFormdev = {}
120 try {
121 //解析16进制数据
122 dataFormdev = JSON.parse(message)
123 console.log(dataFormdev)
124 //赋值语句
125 that.setData({
126 temp: dataFormdev.temp,
127 humi: dataFormdev.humi,
128 led: dataFormdev.led,
129 beep: dataFormdev.beep
130 })
131
132 } catch (error) {
133 console.log('json解析失败', error)
134
135 }
136 })
137
138 },
139
140})
141