当前位置:   article > 正文

基于ESP32测温湿度上传到OneNET并通过微信小程序控制,查看,下发指令_esp32手机app远程控制

esp32手机app远程控制

  1. 项目背景

目前,科学技术发展十分迅速,其渗透到各行各业以及生活的方方面面,室内设计和高科技结合便出现了“智能家居”。所谓智能家居就是以居住场所为平台,利用物联网、传感器、智能控制技术将各种家用电器联系起来,实现居住环境的智能化、自动化、人性化。通过语音控制、远程控制、预约控制、个性化设计、一键控制等功能进一步提高生活的舒适性、便利性、安全性。

2.设计目标

本系统主要分为三大模块,分别为传感器监测模块,自动报警模块和远程控制模块。传感器监测模块包括对环境的温湿度和空气质量监测,用户可以在微信小程序上查看到实时传感数据;自动报警模块是当传感数据超过设置的阈值时会进行报警,提醒用户注意火灾的发生;远程控制模块可以通过微信小程序远程控制LED灯,风扇和加湿器的开关,实现了不在家也能远程控制家里的电器的开关。

3.设备端硬件设计

3.1硬件总体设计

硬件总体框架如下图所示。

3.2单片机选型及传感器选型

3.2.1 ESP32模块

SP32-WROOM-32 是一款通用型Wi-Fi+BT+BLE+MCU的模组,功能强大,用途广泛,可以用于低功耗传感器网络和要求极高的任务,例如语音编码、音频流和MP3解码等。ESP32还集成了丰富的外设,包括电容式触摸传感器、霍尔传感器、低噪声传感放大器,SD卡接口、以太网接口、高速SDIO/SPI、UART、I2S 和I2C等。

3.2.2 温湿度模块

本系统采集环境的温湿度选择 DHT11 温湿度传感器。DHT11 数字温湿度传感器采 用的是已校准数字信号输出,它能够同时检测温度和湿度,它使用专用的数字模块采集 技术和温湿度传感技术,能够确保产品的高可靠性与稳定性。 该传感器包括一个电阻式感湿元件和一个 NTC 测温元件,利用元件的电气特性随 温湿度的变化测量出环境的温湿度,元件与一个高性能 8 位单片机相连接。该产品具有 高品质、响应快、抗干扰强、性价比高等优点。低功耗与非常小的体积使得它能够被应 用于各种复杂的场景。DHT11 为 4 针单排引脚封装,连接方便。DHT11 温湿度模块实物图如下图所示。

         

4.直接上代码

  4.1.1、设备怎么连上网

  1. #include <WiFi.h>
  2. const char* ssid = "baby"; //wifi名称
  3. const char* password = "13456789";//wifi密码
  4. void setupWifi(){
  5. delay(10);
  6. Serial.println("连接WIFI");
  7. WiFi.begin(ssid, password);
  8. while (!WiFi.isConnected())
  9. {
  10. Serial.print(".");
  11. delay(500);
  12. }
  13. Serial.println("OK");
  14. Serial.println("Wifi连接成功");
  15. }

  4.1.2、MQTT接入地址

 1、mqtt协议的接口端号是6002,而mqtts协议的接口端号是1883

  1. const char *mqtt_server = "183.230.40.96"; //onenet 的 IP地址
  2. const int port = 6002; //端口号

2、数据如何发送给onenet

这里我们需要查阅onenet的相关文档

OneNET - 中国移动物联网开放平台

  1. #define mqtt_devid "945965335" //设备ID
  2. #define mqtt_pubid "577632" //产品ID
  3. //鉴权信息
  4. #define mqtt_password "123456" //鉴权信息
  5. char msg_buf[200]; //发送信息缓冲区
  6. char msgJson[75]; //要发送的json格式的数据
  7. unsigned short json_len = 0; //json长度
  8. //信息模板
  9. char dataTemplate[] = "{\"temp\":%.2f,\"humi\":%.2f,\"led\":%d}"; // temp humi led要与onenet相对应
  1. void sendTempAndHumi()
  2. {
  3. if (client.connected())
  4. {
  5. //dht.readHumidity()
  6. snprintf(msgJson,75,dataTemplate,dht.readTemperature(),dht.readHumidity(),god);
  7. json_len = strlen(msgJson); //msgJson的长度
  8. msg_buf[0] = char(0x03); //要发送的数据必须按照ONENET的要求发送, 根据要求,数据第一位是3
  9. msg_buf[1] = char(json_len >> 8); //数据第二位是要发送的数据长度的高八位
  10. msg_buf[2] = char(json_len & 0xff); //数据第三位是要发送数据的长度的低八位
  11. memcpy(msg_buf + 3, msgJson, strlen(msgJson)); //从msg_buf的第四位开始,放入要传的数据msgJson
  12. msg_buf[3 + strlen(msgJson)] = 0; //添加一个0作为最后一位, 这样要发送的msg_buf准备好了
  13. Serial.print("public the data:");
  14. Serial.print(msgJson);
  15. client.publish("$dp", (uint8_t *)msg_buf, 3+strlen(msgJson));
  16. //发送数据到主题
  17. delay(500);
  18. }
  19. }

在setup()函数中定义了每5秒发一次信息到OneNET平台

  1. tim1.attach(5, sendTempAndHumi); //定时每5秒调用一次发送数据函数sendTempAndHumi

3、在 setup()函数订阅命令下发主题

  client.setCallback(callback); //订阅命令下发主题
  1. //收到主题下发的回调, 注意这个回调要实现三个形参 1:topic 主题, 2: payload: 传递过来的信息 3: length: 长度
  2. void callback(char *topic, byte *payload, unsigned int length)
  3. {
  4. Serial.print("Message arrived [");
  5. Serial.print(topic);
  6. Serial.print("] ");
  7. for (int i = 0; i < length; i++) {
  8. Serial.print((char)payload[i]);
  9. }
  10. Serial.println();
  11. if ((char)payload[0] == '0') {
  12. digitalWrite(led, LOW); //
  13. god=0;
  14. } if ((char)payload[0] == '1') {
  15. digitalWrite(led, HIGH); //
  16. god=1;
  17. }
  18. else{}
  19. }

  4.1.3、测温湿度

使用DHT11模块,调用库

#include "DHT.h"

定义DHT11,数据引脚我接在IO13口

  1. #define DHTPIN 13 // io13
  2. #define DHTTYPE DHT11 // DHT 11
  3. DHT dht(DHTPIN, DHTTYPE);

 5、总代码(当然了这个是新手必备,只需要一个DHT11和一个LED灯就可以实现的)

  1. #include <WiFi.h>
  2. #include "DHT.h"
  3. #include "PubSubClient.h"
  4. #include "Ticker.h"
  5. #define DHTPIN 13
  6. #define DHTTYPE DHT11 // DHT 11
  7. #define led 18 //灯的接口
  8. DHT dht(DHTPIN, DHTTYPE);
  9. int god=0;
  10. const char *ssid = "baby"; //wifi名称
  11. const char *password = "12345671";//wifi密码
  12. const char *mqtt_server = "183.230.40.96"; //onenet 的 IP地址
  13. const int port = 6002; //端口号
  14. #define mqtt_devid "999999735" //设备ID
  15. #define mqtt_pubid "599995" //产品ID
  16. //鉴权信息
  17. #define mqtt_password "123456" //鉴权信息
  18. WiFiClient espClient; //创建一个WIFI连接客户端
  19. PubSubClient client(espClient); // 创建一个PubSub客户端, 传入创建的WIFI客户端
  20. char msg_buf[200]; //发送信息缓冲区
  21. char msgJson[75]; //要发送的json格式的数据
  22. unsigned short json_len = 0; //json长度
  23. //信息模板
  24. char dataTemplate[] = "{\"temp\":%.2f,\"humi\":%.2f,\"led\":%d}"; // temp humi要与onenet相对应
  25. Ticker tim1; //定时器,用来循环上传数据
  26. //连接WIFI
  27. void setupWifi(){
  28. delay(10);
  29. Serial.println("连接WIFI");
  30. WiFi.begin(ssid, password);
  31. while (!WiFi.isConnected())
  32. {
  33. Serial.print(".");
  34. delay(500);
  35. }
  36. Serial.println("OK");
  37. Serial.println("Wifi连接成功");
  38. }
  39. void setup() {
  40. Serial.begin(115200);
  41. pinMode(led,OUTPUT);//输出
  42. setupWifi(); //调用函数连接WIFI
  43. Serial.print(F("DHT11 test!"));
  44. dht.begin();
  45. client.setServer(mqtt_server, port); //设置客户端连接的服务器,连接Onenet服务器, 使用6002端口
  46. client.connect(mqtt_devid, mqtt_pubid, mqtt_password); //客户端连接到指定的产品的指定设备.同时输入鉴权信息
  47. if (client.connected())
  48. {
  49. Serial.print("OneNet is connected!");//判断以下是不是连好了.
  50. }
  51. //client.setCallback(callback); //设置好客户端收到信息是的回调
  52. client.setCallback(callback); //订阅命令下发主题
  53. tim1.attach(5, sendTempAndHumi); //定时每5秒调用一次发送数据函数sendTempAndHumi
  54. }
  55. void loop() {
  56. delay(5000);
  57. float h = dht.readHumidity();
  58. float t = dht.readTemperature();
  59. float f = dht.readTemperature(true);
  60. if (isnan(h) || isnan(t) || isnan(f)) {
  61. Serial.println(F("Failed to read from DHT sensor!\n"));
  62. return;
  63. }
  64. //可以让我们通过串口查看数据
  65. Serial.print(F("Humidity: "));
  66. Serial.print(h);
  67. Serial.print(F("% Temperature: "));
  68. Serial.print(t);
  69. Serial.print(F("℃ \n "));
  70. if (!WiFi.isConnected()) //先看WIFI是否还在连接
  71. {
  72. setupWifi();
  73. }
  74. if (!client.connected()) //如果客户端没连接ONENET, 重新连接
  75. {
  76. clientReconnect();
  77. delay(100);
  78. }
  79. client.loop(); //客户端循环检测
  80. }
  81. void sendTempAndHumi()
  82. {
  83. if (client.connected())
  84. {
  85. //dht.readHumidity()
  86. snprintf(msgJson,75,dataTemplate,dht.readTemperature(),dht.readHumidity(),god);
  87. json_len = strlen(msgJson); //msgJson的长度
  88. msg_buf[0] = char(0x03); //要发送的数据必须按照ONENET的要求发送, 根据要求,数据第一位是3
  89. msg_buf[1] = char(json_len >> 8); //数据第二位是要发送的数据长度的高八位
  90. msg_buf[2] = char(json_len & 0xff); //数据第三位是要发送数据的长度的低八位
  91. memcpy(msg_buf + 3, msgJson, strlen(msgJson)); //从msg_buf的第四位开始,放入要传的数据msgJson
  92. msg_buf[3 + strlen(msgJson)] = 0; //添加一个0作为最后一位, 这样要发送的msg_buf准备好了
  93. Serial.print("public the data:");
  94. Serial.print(msgJson);
  95. client.publish("$dp", (uint8_t *)msg_buf, 3+strlen(msgJson));
  96. //发送数据到主题
  97. delay(500);
  98. }
  99. }
  100. //收到主题下发的回调, 注意这个回调要实现三个形参 1:topic 主题, 2: payload: 传递过来的信息 3: length: 长度
  101. void callback(char *topic, byte *payload, unsigned int length)
  102. {
  103. Serial.print("Message arrived [");
  104. Serial.print(topic);
  105. Serial.print("] ");
  106. for (int i = 0; i < length; i++) {
  107. Serial.print((char)payload[i]);
  108. }
  109. Serial.println();
  110. if ((char)payload[0] == '0') {
  111. digitalWrite(led, LOW); //
  112. god=0;
  113. } if ((char)payload[0] == '1') {
  114. digitalWrite(led, HIGH); //
  115. god=1;
  116. }
  117. else{}
  118. }
  119. void clientReconnect()
  120. {
  121. while (!client.connected()) //再重连客户端
  122. {
  123. Serial.print("reconnect MQTT...");
  124. if (client.connect(mqtt_devid, mqtt_pubid, mqtt_password))
  125. {
  126. Serial.print("connected");
  127. }
  128. else
  129. {
  130. Serial.print("failed");
  131. Serial.print(client.state());
  132. Serial.print("try again in 5 sec");
  133. delay(5000);
  134. }
  135. }
  136. }

6、微信开发者工具

 

 

自己创建一个项目,直接替换index.js,index.wxml,index.wxss

index.js

  1. // index.js
  2. // 获取应用实例
  3. const app = getApp()
  4. const mqtt=require('../../utils/mqtt')
  5. Page({
  6. data: {
  7. motto: 'Hello World',
  8. userInfo: {},
  9. hasUserInfo: false,
  10. canIUse: wx.canIUse('button.open-type.getUserInfo'),
  11. canIUseGetUserProfile: false,
  12. canIUseOpenData: wx.canIUse('open-data.type.userAvatarUrl') && wx.canIUse('open-data.type.userNickName') // 如需尝试获取用户信息可改为false
  13. },
  14. // 事件处理函数
  15. bindViewTap() {
  16. wx.navigateTo({
  17. url: '../logs/logs'
  18. })
  19. },
  20. onLoad() {
  21. if (wx.getUserProfile) {
  22. this.setData({
  23. canIUseGetUserProfile: true
  24. })
  25. }
  26. },
  27. getUserProfile(e) {
  28. // 推荐使用wx.getUserProfile获取用户信息,开发者每次通过该接口获取用户个人信息均需用户确认,开发者妥善保管用户快速填写的头像昵称,避免重复弹窗
  29. wx.getUserProfile({
  30. desc: '展示用户信息', // 声明获取用户个人信息后的用途,后续会展示在弹窗中,请谨慎填写
  31. success: (res) => {
  32. console.log(res)
  33. this.setData({
  34. userInfo: res.userInfo,
  35. hasUserInfo: true
  36. })
  37. }
  38. })
  39. },
  40. getUserInfo(e) {
  41. // 不推荐使用getUserInfo获取用户信息,预计自2021413日起,getUserInfo将不再弹出弹窗,并直接返回匿名的用户个人信息
  42. console.log(e)
  43. this.setData({
  44. userInfo: e.detail.userInfo,
  45. hasUserInfo: true
  46. })
  47. },
  48. points:function(e) {
  49. var that = this
  50. wx.request({
  51. //设备ID
  52. //api-key
  53. url: 'http://api.heclouds.com/devices/xxxxxxxxxx/datapoints?', //xxxxxxxxxx这里填写你的设备id
  54. header:{
  55. "api-key":"5oXSCXaNrBBlsQm6YNWU3wtHu1U=" //这里写你的api-key
  56. },
  57. data:{
  58. limit:1
  59. },
  60. method :"GET",
  61. //获取成功
  62. success:function(res){
  63. that.setData({
  64. light:res.data.data.datastreams[0].datapoints[0].value,
  65. wendu:res.data.data.datastreams[1].datapoints[0].value,
  66. shidu:res.data.data.datastreams[3].datapoints[0].value, //这里的shidu要跟wxml{{shidu}} 名字相同
  67. })
  68. }
  69. })
  70. },
  71. openled:function(e){
  72. let pafload
  73. if(e.detail.value==true)
  74. pafload = 1
  75. else
  76. pafload =0
  77. console.log(pafload)
  78. wx.request({
  79. url: 'http://api.heclouds.com/cmds?device_id=xxxxxxxxxx',
  80. //*号这里写你设备id//设备ID//api-key
  81. header:{
  82. 'content-type':'application/json',
  83. "api-key":"5oXSCXaNrQm6YNWU3wtHu1U=" //这里写你的api-key
  84. },
  85. method :"POST",
  86. data:pafload,//数据1是为灯开
  87. success(res){
  88. console.log("控制成功,已开灯")
  89. console.log(res)
  90. console.log(res.data);
  91. }
  92. })
  93. },
  94. /**
  95. * 生命周期函数--监听页面加载 */
  96. onLoad: function (options) {
  97. this.points() //这个是我获取onenet数据的函数
  98. var that=this
  99. setInterval(function(){
  100. that.points();
  101. },3000 //这里我设置3秒刷新一次
  102. )
  103. },
  104. })

index.wxml

  1. <!--pages/index/index.wxml-->
  2. <view class= "content">
  3. <view class= "zm">
  4. <text class="zm1">照明开关</text>
  5. <switch class="kai" id='1' bindchange="openled"/>
  6. </view>
  7. <view style="flex:1;width:100%">
  8. <label class="xia">
  9. <text class="zm1">当前温度:{{wendu}}°C</text>
  10. </label>
  11. </view>
  12. <view style="flex:1;width:100%">
  13. <label class="xia">
  14. <text class="zm1">当前湿度:{{shidu}} %</text>
  15. </label>
  16. </view>
  17. </view>

index.wxss

  1. /* pages/index/index.wxss */
  2. page {
  3. background: #f6f6f6;
  4. display: flex;
  5. flex-direction: column;
  6. justify-content: flex-start;
  7. }
  8. .headTitle{
  9. width: 100%;
  10. height: 80rpx;
  11. background-color: #ffffff;
  12. overflow:hidden ;/** 设置超出内容隐藏 */
  13. white-space:nowrap; /*设置超出不换行 */
  14. border-bottom :1px solid #F3F3F3;
  15. }
  16. .headTitle .titleItem{
  17. display: inline-block;
  18. line-height:80rpx;
  19. color: #889999;
  20. font-size:34rpx;
  21. margin: 0 20rpx;
  22. }
  23. .headTitle .selctItem{
  24. color: #000000;
  25. font-weight: bold;
  26. }
  27. .itemView{
  28. width: 100%;
  29. height:180rpx;
  30. position: relative;
  31. border-bottom: 1px solid #F3F3F3;
  32. }
  33. .zm{
  34. margin-top: 20rpx;
  35. border:1px solid#ebe4e286;
  36. width:750rpx;
  37. height: 100rpx;
  38. border-radius: 5px;
  39. font-size: 36;
  40. font-weight: bold;
  41. line-height: 80rpx;
  42. color: #32d5e0;
  43. text-align: center;
  44. display: flex;
  45. position: relative;/*父元素位置要设置为相对*/
  46. }
  47. .login-btn{
  48. width: 40%!important;
  49. background-color: #33ff33;
  50. color: white;
  51. font-weight: normal;
  52. }
  53. .content{
  54. margin-top: 20rpx;
  55. border:1px solid#ebe4e286;
  56. width:750rpx;
  57. height: 600rpx;
  58. border-radius: 5px;
  59. font-size: 36;
  60. font-weight: bold;
  61. line-height: 80rpx;
  62. color: #32d5e0;
  63. text-align: center;
  64. flex-direction: column;
  65. display: flex;
  66. }
  67. .xia{
  68. justify-content: space-between;
  69. }
  70. .zm1{
  71. position: absolute; /* 要约束所在位置的子元素的位置要设置成绝对 */
  72. left: 30rpx; /* 靠右调节 */
  73. }
  74. .radio{
  75. display:inline-block; /* 横向布局*/
  76. }
  77. .kai{
  78. position: absolute; /* 要约束所在位置的子元素的位置要设置成绝对 */
  79. right: 100rpx; /* 靠右调节 */
  80. }
  81. .mos{
  82. left: 120rpx; /* 靠右调节 */
  83. height: 200rpx;
  84. }

微信小程序链接

百度网盘

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号