这里写自定义目录标题
案例成果
1.Ardino写入部分
c
复制代码
#include <WiFi.h> // ESP32 WiFi库
#include <PubSubClient.h> // MQTT客户端库
#include <DHT.h> // DHT传感器库
// WiFi配置
const char *ssid = "601B"; // WiFi名称
const char *password = "12345678"; // WiFi密码
// MQTT服务器配置
const char* mqtt_server = "bemfa.com"; // MQTT服务器地址
const int mqtt_server_port = 9501; // MQTT服务器端口
#define ID_MQTT "0c876e1774cc3bd27de1d5d1bfc61c90" // 您的客户端ID
// 创建WiFi和MQTT客户端实例
WiFiClient espClient;
PubSubClient client(espClient);
// 定义引脚 - 注意:ESP32使用GPIO编号,而不是NodeMCU的D编号
#define ledpin 2 // LED指示灯连接的引脚,用于远程控制开关 (GPIO2)
#define eqpin 3 // 地震传感器连接的引脚,用于检测震动 (GPIO3)
#define beeppin 18 // 蜂鸣器连接的引脚,用于警报提示
#define flapin 5 // 火灾传感器连接的引脚,用于检测火情 (GPIO5)
#define dhtpin 15 // DHT11温湿度传感器连接的引脚 (GPIO15)
#define DHTTYPE DHT11 // 定义使用的温湿度传感器类型为DHT11
#define airpin 34 // 空气质量传感器连接的模拟引脚,用于检测空气污染程度 (GPIO34 - ADC6)
// 创建DHT传感器对象
DHT dht(dhtpin, DHTTYPE);
// 定义状态变量
bool val1 = 0; // 地震传感器状态
bool val2 = 0; // 火灾传感器状态
// MQTT主题 - 与微信小程序匹配的命名
const char* mqtt_switch_topic = "switch"; // LED开关主题(接收控制命令)
const char* mqtt_temper_topic = "temper"; // 温度主题(发布温度数据)
const char* mqtt_humid_topic = "humid"; // 湿度主题(发布湿度数据)
const char* mqtt_air_topic = "air"; // 空气质量主题(发布空气质量数据)
const char* mqtt_earthquake_topic = "earthquake"; // 地震主题(发布地震状态)
const char* mqtt_flame_topic = "flame"; // 火灾主题(发布火灾状态)
const char* mqtt_beep_topic = "beep"; // 蜂鸣器主题(可选)
// WiFi连接函数
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
// MQTT消息接收回调函数
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("订阅的信息为 [");
Serial.print(topic);
Serial.print("] ");
// 将接收到的字节数组转换为字符串
String message;
for (int i = 0; i < length; i++) {
message += (char)payload[i];
}
Serial.println(message);
// 控制LED
if (strcmp(topic, mqtt_switch_topic) == 0) {
if (message == "on") {
digitalWrite(ledpin, HIGH);
Serial.println("打开 LED 灯");
} else if (message == "off") {
digitalWrite(ledpin, LOW);
Serial.println("关闭 LED 灯");
}
}
}
// 重连函数
void reconnect() {
// 循环直到重新连接
while (!client.connected()) {
Serial.print("尝试连接MQTT...");
// 尝试连接
if (client.connect(ID_MQTT)) {
Serial.println("connected");
// 连接成功后,订阅LED控制主题
client.subscribe(mqtt_switch_topic);
Serial.print("已订阅主题: ");
Serial.println(mqtt_switch_topic);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
// 初始化
void setup() {
// 初始化串口
Serial.begin(115200);
Serial.println("初始化系统...");
// 初始化DHT传感器
dht.begin();
// 设置引脚模式
pinMode(ledpin, OUTPUT);
digitalWrite(ledpin, LOW);
// 设置传感器引脚
pinMode(eqpin, INPUT);
pinMode(flapin, INPUT);
pinMode(beeppin, OUTPUT);
pinMode(airpin, INPUT); // 模拟输入
// 连接WiFi
setup_wifi();
// 设置MQTT服务器和回调
client.setServer(mqtt_server, mqtt_server_port);
client.setCallback(callback);
// 连接MQTT服务器
reconnect();
Serial.println("系统初始化完成!");
}
void loop() {
// 检查MQTT连接状态
if (!client.connected()) {
reconnect(); // 重新连接
}
// 处理MQTT消息
client.loop();
// 读取温湿度
float h = dht.readHumidity();
float t = dht.readTemperature();
// 检查温湿度读取是否成功
if (isnan(h) || isnan(t)) {
Serial.println("Failed to read from DHT sensor!");
} else {
// 输出温湿度
Serial.print("湿度: ");
Serial.print(h);
Serial.print("%, 温度: ");
Serial.print(t);
Serial.println("°C");
// 转换为字符串用于发布
String tempMsg = String(t);
String humidMsg = String(h);
// 发布温湿度数据到MQTT
client.publish(mqtt_temper_topic, tempMsg.c_str());
client.publish(mqtt_humid_topic, humidMsg.c_str());
}
// 读取空气质量
int airval = analogRead(airpin);
Serial.print("空气质量: ");
Serial.println(airval);
String airMsg = String(airval);
client.publish(mqtt_air_topic, airMsg.c_str());
// 读取地震传感器状态
val1 = digitalRead(eqpin);
if (val1 == 0) {
// 发布地震警报
client.publish(mqtt_earthquake_topic, "off");
Serial.println("无震感");
client.publish(mqtt_beep_topic, "off"); // 前端无需显示蜂鸣器的状态
}
else {
// 发布地震警报
client.publish(mqtt_earthquake_topic, "on");
Serial.println("有震感");
client.publish(mqtt_beep_topic, "on"); // 前端无需显示蜂鸣器的状态
}
// 读取火灾传感器状态
val2 = digitalRead(flapin);
Serial.print("火灾传感器状态: ");
Serial.println(val2);
if (val2 == 1) {
// 发布火灾警报
client.publish(mqtt_flame_topic, "off");
Serial.println("无火灾");
digitalWrite(beeppin, HIGH);
}
else {
// 发布火灾警报
client.publish(mqtt_flame_topic, "on");
Serial.println("有火灾");
digitalWrite(beeppin, LOW);
}
// 延时100毫秒
delay(100);
}
2.微信小程序JS部分
c
复制代码
// pages/class/class.js
const app = getApp()
import mqtt from '../../utils/mqtt.min'
Page({
data: {
// 主题定义
ledtopic: "switch", // LED开关主题
eqtopic: "earthquake", // 地震传感器主题
fhtopic: "flame", // 火灾传感器主题
wdtopic: "temper", // 温度传感器主题
sdtopic: "humid", // 湿度传感器主题
kqtopic: "air", // 空气质量传感器主题
beeptopic: "beep", // 新增:蜂鸣器主题
uid: "0c876e1774cc3bd27de1d5d1bfc61c90", // 设备唯一ID
// 传感器状态
qustatus: "无震感", // 地震状态
flastatus: "无火灾", // 火灾状态
wdval: "未知", // 温度值
sdval: "未知", // 湿度值
airval: "未知", // 空气质量值
beepstatus: "关闭", // 新增:蜂鸣器状态
isThemeOn: false, // 开关状态,默认关闭
device_status: "离线", // 设备连接状态
client: null // MQTT客户端
},
// MQTT连接方法
mqttConnect() {
var that = this;
var options = {
keepalive: 60, // 心跳间隔
clean: true, // 清除会话
protocolVersion: 4, // MQTT协议版本
clientId: that.data.uid // 客户端ID
};
// 连接到MQTT服务器
that.data.client = mqtt.connect('wxs://bemfa.com:9504/wss', options);
// 连接成功回调
that.data.client.on('connect', function() {
console.log("连接服务器成功");
that.setData({
device_status: "在线"
});
// 订阅所有传感器主题
// 订阅地震传感器主题
that.data.client.subscribe(that.data.eqtopic, function(err) {
if(err) console.log(err);
});
// 订阅火灾传感器主题
that.data.client.subscribe(that.data.fhtopic, function(err) {
if(err) console.log(err);
});
// 订阅温度传感器主题
that.data.client.subscribe(that.data.wdtopic, function(err) {
if(err) console.log(err);
});
// 订阅湿度传感器主题
that.data.client.subscribe(that.data.sdtopic, function(err) {
if(err) console.log(err);
});
// 订阅空气质量传感器主题
that.data.client.subscribe(that.data.kqtopic, function(err) {
if(err) console.log(err);
});
// 新增:订阅蜂鸣器主题
that.data.client.subscribe(that.data.beeptopic, function(err) {
if(err) console.log(err);
});
});
// 接收消息回调
that.data.client.on('message', function(topic, message) {
var msg = message.toString();
// 处理不同主题的消息
// 地震传感器消息
if(topic === that.data.eqtopic) {
that.setData({
qustatus: msg === 'on' ? '有地震' : '无地震'
});
}
// 火灾传感器消息
else if(topic === that.data.fhtopic) {
that.setData({
flastatus: msg === 'on' ? '有火灾' : '无火灾'
});
}
// 温度传感器消息
else if(topic === that.data.wdtopic) {
that.setData({
wdval: msg
});
}
// 湿度传感器消息
else if(topic === that.data.sdtopic) {
that.setData({
sdval: msg
});
}
// 空气质量传感器消息
else if(topic === that.data.kqtopic) {
that.setData({
airval: msg
});
}
// 新增:蜂鸣器消息
else if(topic === that.data.beeptopic) {
that.setData({
beepstatus: msg === 'on' ? '开启' : '关闭'
});
}
});
// 重连回调
that.data.client.on('reconnect', function() {
console.log("重新连接");
that.setData({
device_status: "连接中"
});
});
// 连接错误回调
that.data.client.on('error', function(error) {
console.log("连接失败", error);
that.setData({
device_status: "离线"
});
});
},
// 页面加载时连接MQTT服务器
onLoad() {
this.mqttConnect()
},
// 开关点击事件处理
onThemeSwitchTap: function() {
if(this.data.client && this.data.client.connected) {
// 切换开关状态
const message = this.data.isThemeOn ? 'off' : 'on';
// 发布消息到LED开关主题
this.data.client.publish(this.data.ledtopic, message);
// 更新UI状态
this.setData({
isThemeOn: !this.data.isThemeOn
});
} else {
console.log("MQTT未连接");
}
}
})
3.微信小程序xml部分
c
复制代码
<!--pages/znjj/znjj.wxml-->
<view class="imag4_src"></view>
<image class="imag4" src="/img/znjj.png"></image>
<view class="spacer"></view>
<view class="container1">
<view class="view1">
<view class="img_wd">
<view class="content-row">
<image class="img1" src="/img/wd.png"></image>
<text>温度</text>
</view>
<view class="loading-container">
<!-- 修改:绑定温度数据 -->
<text class="loading-text">{{wdval}}</text>
</view>
</view>
</view>
<view class="view2">
<view class="img_wd">
<view class="content-row">
<image class="img1" src="/img/sd.png"></image>
<text>湿度</text>
</view>
<view class="loading-container">
<!-- 修改:绑定湿度数据 -->
<text class="loading-text">{{sdval}}</text>
</view>
</view>
</view>
<view class="view3">
<view class="img_wd">
<view class="content-row">
<image class="img1" src="/img/PM2.5.png"></image>
<text>空气</text>
</view>
<view class="loading-container">
<!-- 修改:绑定空气质量数据 -->
<text class="loading-text">{{airval}}</text>
</view>
</view>
</view>
</view>
<view class="spacer"></view>
<view class="container2">
<view class="view4">
<view class="img_wd">
<view class="content-row">
<image class="img1" src="/img/hy.png"></image>
<text>防火</text>
</view>
<view class="loading-container">
<!-- 修改:绑定火灾状态 -->
<text class="loading-text">{{flastatus}}</text>
</view>
</view>
</view>
<view class="view5">
<view class="img_wd">
<view class="content-row">
<image class="img1" src="/img/dz.png"></image>
<text>地震</text>
</view>
<view class="loading-container">
<text class="loading-text">{{qustatus}}</text>
</view>
</view>
</view>
<view class="view6">
<view class="img_wd">
<view class="content-row">
<image class="img1" src="/img/kt.png"></image>
<text>空调</text>
</view>
<view class="switch-container">
<button class="theme-switch-button" bindtap="onThemeSwitchTap">
{{isThemeOn ? 'on' : 'off'}}
</button>
</view>
</view>
</view>
</view>
<view class="spacer"></view>
<view class="container3">
<view class="view7">
<view class="img_wd">
<view class="content-text">
<text>设备状态</text>
<text class="module">{{device_status}}</text>
</view>
</view>
</view>
<view class="view8">
<view class="img_wd">
<view class="content-text">
<text>火灾告警</text>
<view wx:if="{{flastatus == '有火灾'}}">
<image class="img5" src="/img/hz_on.png"></image>
</view>
<view wx:else>
<image class="img5" src="/img/hz_off.png"></image>
</view>
</view>
</view>
</view>
<view class="view9">
<view class="img_wd">
<view class="content-text">
<text>地震告警</text>
<!-- 修改:使用qustatus而不是eqstatus -->
<view wx:if="{{qustatus == '有地震'}}">
<image class="img5" src="/img/dz_on.png"></image>
</view>
<view wx:else>
<image class="img5" src="/img/dz_off.png"></image>
</view>
</view>
</view>
</view>
</view>
4. 微信小程序CSS部分
c
复制代码
/* 顶部标题图片容器样式 */
.imag4_src{
display: block; /* 设置为块级元素,占据整行 */
width: 100%; /* 宽度占满父容器 */
}
/* 顶部标题图片样式 */
.imag4{
width: 350px; /* 设置固定宽度 */
height: 200px; /* 设置固定高度 */
justify-content: center; /* 水平居中对齐 */
border: 1px solid #000; /* 添加1像素黑色边框 */
border-radius: 10px; /* 设置10像素圆角 */
margin: 20px; /* 四周添加20像素外边距 */
box-shadow: 5px 5px 15px rgba(0,0,0,0.3); /* 添加阴影效果:右下偏移,模糊度,颜色 */
transition: transform 0.3s ease; /* 添加变换过渡效果:持续0.3秒,缓动函数ease */
}
/* 标题图片悬停效果 */
.imag4:hover{
transform: scale(1.05); /* 悬停时放大图片到原尺寸的1.05倍 */
}
/* 垂直间隔元素 */
.spacer{
height: 10px; /* 创建10像素高度的垂直间隔 */
}
/* 第一行和第二行容器共同样式 */
.container1,
.container2{
display: flex; /* 设置为Flex布局容器 */
flex-direction: row; /* 子元素水平排列(默认值) */
justify-content: center; /* 子元素在主轴(水平)上居中对齐 */
}
/* 第一行和第二行中所有方块的共同样式 */
.container1 .view1,
.container1 .view2,
.container1 .view3,
.container2 .view4,
.container2 .view5,
.container2 .view6{
width: 90px; /* 设置宽度为90像素 */
height: 100px; /* 设置高度为100像素 */
margin: 20px; /* 四周添加20像素外边距 */
position: relative; /* 设置相对定位,作为内部元素的定位参考 */
background-color: transparent; /* 背景透明(但随后被单独的规则覆盖) */
display: flex; /* 设置为Flex布局容器 */
align-items: lsft; /* 注意:这里有拼写错误,应为'left',垂直方向左对齐 */
justify-content: center; /* 水平居中对齐 */
border: 2px solid rgb(291,214,214); /* 注意:RGB值错误,291超出范围(0-255) */
box-shadow: 0 0 10px rgba(37,37,37,0.5); /* 添加阴影效果,模拟立体边框 */
}
/* 第一行各模块的背景颜色 */
.container1 .view1 { background-color: #e3ece2; } /* 温度模块:淡绿色 */
.container1 .view2 { background-color: #ccd4cb; } /* 湿度模块:灰绿色 */
.container1 .view3 { background-color: #e5f3ee; } /* 空气模块:浅蓝绿色 */
/* 第二行各模块的背景颜色 */
.container2 .view4 { background-color: #f7e7e9; } /* 防火模块:淡粉色 */
.container2 .view5 { background-color: #d7eef7; } /* 地震模块:淡蓝色 */
.container2 .view6 { background-color: #e3e4f1; } /* 空调模块:淡紫色 */
/* 模块内容容器样式 */
.img_wd{
justify-content: flex-start; /* 内容在水平方向靠左对齐 */
align-items: flex-start; /* 内容在垂直方向靠上对齐 */
width: 100px; /* 设置宽度为100像素 */
height: 100px; /* 设置高度为100像素 */
position: relative; /* 设置相对定位,供内部元素参考 */
}
/* 图标和文字行样式 */
.content-row{
margin-top: 1px; /* 顶部添加1像素外边距 */
display: flex; /* 设置为Flex布局容器 */
align-items: center; /* 子元素在垂直方向居中对齐 */
margin-left: 3px; /* 左侧添加3像素外边距 */
}
/* 图标样式 */
.img1{
width: 30px; /* 设置图标宽度为30像素 */
height: 30px; /* 设置图标高度为30像素 */
border: 1px solid rgb(211,209,209); /* 添加浅灰色边框 */
border-radius: 10px; /* 设置10像素圆角 */
margin: 3px; /* 四周添加3像素外边距 */
box-shadow: 5px 5px 15px rgba(0, 0, 0, 0.3); /* 添加阴影效果 */
transition: transform 0.3s ease; /* 添加变换过渡效果 */
margin-right: 5px; /* 右侧添加5像素外边距,与文字分开 */
}
/* 数据加载容器样式 */
.loading-container{
margin-top: 20px; /* 顶部添加20像素外边距 */
display: flex; /* 设置为Flex布局容器 */
justify-content: center; /* 水平居中对齐 */
align-items: center; /* 垂直居中对齐 */
}
/* 加载文本样式 */
.loading-text{
justify-content: center; /* 水平居中对齐(在flex子项中) */
align-items: center; /* 垂直居中对齐(在flex子项中) */
font-size: 16px; /* 设置字体大小为16像素 */
color: #333; /* 设置字体颜色为深灰色 */
height: 20px; /* 设置高度为20像素 */
}
/* 第三行容器样式 */
.container3{
display: flex; /* 设置为Flex布局容器 */
flex-direction: row; /* 子元素水平排列 */
justify-content: center; /* 水平居中对齐 */
/* 注释提到暂时移除其他样式以进行故障排除 */
}
/* 第三行各模块共同样式 */
.container3 .view7,
.container3 .view8,
.container3 .view9{
width: 90px; /* 设置宽度为90像素 */
height: 100px; /* 设置高度为100像素 */
margin: 20px; /* 四周添加20像素外边距 */
position: relative; /* 设置相对定位 */
background-color: transparent; /* 背景透明(但随后被单独的规则覆盖) */
display: flex; /* 设置为Flex布局容器 */
align-items: left; /* 垂直方向左对齐(注意:这应为vertical-align或align-items:flex-start) */
justify-content: center; /* 水平居中对齐 */
border: 2px solid rgb(219, 214, 214); /* 添加浅灰色边框 */
box-shadow: 0 0 10px rgba(37, 37, 37, 0.5); /* 添加阴影效果 */
border-radius: 60px; /* 设置60像素圆角,几乎成为圆形 */
}
/* 第三行各模块的背景颜色 */
.container3 .view7 { background-color: #f1ecec; } /* 设备状态模块:淡红灰色 */
.container3 .view8 { background-color: #f3f8f6; } /* 火灾告警模块:淡青色 */
.container3 .view9 { background-color: #ece6f5; } /* 地震告警模块:淡紫色 */
/* 开关按钮容器样式 */
.switch-container {
width: 60px; /* 设置宽度为60像素 */
height: 30px; /* 设置高度为30像素 */
display: flex; /* 设置为Flex布局容器 */
justify-content: center; /* 水平居中对齐 */
align-items: center; /* 垂直居中对齐 */
margin-top: 20px; /* 顶部添加20像素外边距 */
margin-left: auto; /* 左侧自动外边距,配合右侧自动外边距实现水平居中 */
margin-right: auto; /* 右侧自动外边距,配合左侧自动外边距实现水平居中 */
}
/* 开关按钮样式 */
.theme-switch-button {
height: 30px; /* 设置高度为30像素 */
line-height: 30px; /* 设置行高等于高度,使文字垂直居中 */
background-color: rgb(146, 198, 247); /* 设置淡蓝色背景 */
color: rgb(13, 13, 14); /* 设置几乎黑色的文字颜色 */
border: none; /* 移除默认边框 */
border-radius: 20px; /* 设置20像素圆角,使按钮呈胶囊形 */
text-align: center; /* 文字水平居中 */
font-size: 13px; /* 设置字体大小为13像素 */
border: 1px solid rgb(241, 234, 234); /* 添加浅灰色边框 */
box-shadow: 0 0 10px rgba(2, 8, 27, 0.5); /* 添加阴影效果 */
padding: 0; /* 移除内边距,确保文字居中显示 */
}
/* 文本内容容器样式 */
.content-text {
display: flex; /* 设置为Flex布局容器 */
flex-direction: column; /* 子元素垂直排列 */
align-items: center; /* 水平居中对齐 */
justify-content: flex-start; /* 垂直方向从顶部开始对齐 */
margin-top: 15px; /* 顶部添加15像素外边距 */
width: 100%; /* 宽度占满父容器 */
box-sizing: border-box; /* 边框和内边距包含在宽度内 */
}
/* 模块状态文本样式 */
.module {
margin-top: 10px; /* 顶部添加10像素外边距 */
color: #f74d4d; /* 设置文字颜色为鲜红色 */
font-weight: bold; /* 设置字体为粗体 */
}
/* 告警图标样式 */
.img5{
margin-top: 5px; /* 顶部添加5像素外边距 */
width: 50px; /* 设置宽度为50像素 */
height: 40px; /* 设置高度为40像素 */
}