【智能家居入门2】(MQTT协议、微信小程序、STM32、ONENET云平台)

此篇智能家居入门与前两篇类似,但是是使用MQTT协议接入ONENET云平台,实现微信小程序与下位机的通信,这里相较于使用http协议的那两篇博客,在主程序中添加了独立看门狗防止程序卡死和服务器掉线问题。后续还有使用MQTT协议连接MQTT服务器的智能家居项目。

    • 前言
    • 一、硬件模块
    • 二、连接服务器测试
    • 三、两个协议的对比分析
      • 1、代码结构上:
      • 2、获取服务器数据上:
      • 3、架构上:
    • 四、下位机主要代码
      • 1、接收并解析云平台下发数据:
      • 2、传感器数据上云:
    • 五、微信小程序主要代码
      • 1、index.js
      • 2、index.wxml
    • 六、源码获取

前言

这里给出前两篇使用http协议博客的网址:
①实现数据上云:https://blog.csdn.net/m0_71523511/article/details/135892908
②实现小程序控制下位机:https://blog.csdn.net/m0_71523511/article/details/135907645
在第二篇的博客结尾提出了服务器经常掉线的问题,使用别人编写好的心跳包也没用,因为程序一直卡死在重连中,所以也可以参照本篇的解决办法:加上独立看门狗,隔一段时间喂狗,如果超过时间没喂狗,说明程序多半卡死,此时看门狗处理逻辑中执行初始化esp8266和连接服务器的操作。
③独立看门狗:https://www.bilibili.com/video/BV1th411z7sn/?p=46&spm_id_from=pageDriver&vd_source=2a10d30b8351190ea06d85c5d0bfcb2a
④由于使用到了MQTT协议,想深入了解源码的话可以看看之前的的博客,对MQTT协议进行详解:https://blog.csdn.net/m0_71523511/article/details/135905690

一、硬件模块

1、0.96寸OLED液晶显示屏
2、DHT11温湿度传感器
3、继电器
4、小风扇、小水泵
5、MQ-4、MQ-9
6、esp8266-01s或者esp-12f
7、JLink下载器
8、STM32F103C8T6
大部分在上面说的第一篇博客中有介绍,这里介绍一下继电器、小风扇、小水泵:
①继电器:
由于单片机的io口无法直接驱动小风扇和水泵,这里用继电器充当开关,使用继电器驱动小风扇和小水泵运动。
在这里插入图片描述输入端口:外接5V电源,黑色跳帽可以控制继电器是高电平触发还是低电平触发。
输出端口:从左往右看,分别是NO1/NO2,COM1/COM2,NC1/NC2,代表常开,公共端,常闭三种状态。
继电器的两种状态,开和关,当继电器触发时,为打开状态,NOn口就会被使能,当继电器为关闭状态时,NCn口就会被使能,中间作为公共端连接输出。

硬件连线:
继电器输出端:小风扇红黑两根线子,红线接入继电器的NO1/NO2口,继电器的COM1/COM2拿一根公母杜邦线引出来接入5V电源,小风扇的黑线接STM32的GND口。
在这里插入图片描述
继电器输入端:
在这里插入图片描述
原文链接:https://blog.csdn.net/qq_51868810/article/details/127792611

②小风扇、小水泵:
这两个小东西就只有电源线和底线,给5v输入即可转动起来:
在这里插入图片描述
在这里插入图片描述

二、连接服务器测试

如果想单独先使用esp8266测试是否能正常与服务器通信的话可以参考这篇博客,不会创建产品也可以看:
https://blog.csdn.net/m0_71523511/article/details/135887108
需要注意的点:
①创建产品时要选择MQTT协议那个目录下进行创建
②AT指令中的IP地址和端口号要换成:183.230.40.39 6002
③需要记住的有:产品ID、鉴权信息(创建产品时自己填写的)、Master-APIkey、设备ID

三、两个协议的对比分析

1、代码结构上:

相较于使用http协议连接onenet,使用mqtt协议需要多几个源文件:onenet.c、cJSON.c、MqttKit.c。
①onenet.c是与onenet平台的数据交互接口层,通过调用MqttKit.c和esp8266.c中的库函数实现与云平台的通信,
②MqttKit.c是MQTT协议库,是MQTT协议最底层,由onenet.c进行调用。前面两个都是大神张继瑞开源。
③cJSON.c是一个用于处理JSON数据格式的轻量级C语言库,JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,常用于在不同系统之间传输和存储数据。在对云平台下发数据进行解析时会用到(onenet.c)。
在这里插入图片描述

2、获取服务器数据上:

******使用http协议和MQTT协议连接onenet,最大的不同就是获取onenet云平台数据的方式:
http协议:直接构建HTTP请求报文并调用esp8266_send_data函数发送HTTP请求,并获取返回的字符串。
mqtt协议:不主动发送请求,使用ESP8266_WaitRecive函数等待,如果云平台有数据下发,那就存起来当作变量传入OneNet_RevPro函数,进行消息解析。

3、架构上:

在这里插入图片描述
"请求/响应"和"发布/订阅"是两种不同的通信模式,它们在系统架构和通信方式上有所不同。
①请求/响应:
特点: 在请求/响应模式中,通信的一方发送请求,而另一方回复响应。通信是单向的,有一个明确的请求者和一个响应者。
用途: 这种模式常见于客户端和服务器之间的通信。客户端发送请求,服务器处理请求并返回相应的响应。
②发布/订阅:
特点: 在发布/订阅模式中,消息的发布者将消息发送到一个主题(topic),而订阅者可以选择订阅特定主题以接收相关消息。通信是多对多的,发布者和订阅者之间是松耦合的。
用途: 这种模式常见于事件驱动系统、消息中间件和实时数据更新场景。发布者发布消息到主题,所有订阅该主题的订阅者都会收到消息。
由以上分析很容易得出一个结论:在做环境信息检测这种实时数据更新的项目上,使用MQTT协议更具优势。

四、下位机主要代码

1、接收并解析云平台下发数据:

主循环中使用以下代码接收并跳转:

		dataPtr = ESP8266_GetIPD(10);if(dataPtr != NULL){timeCount = 0;OneNet_RevPro(dataPtr);}

接收到数据后跳转至onenet.c的OneNet_RevPro函数中进行mqtt数据包(报文)解包和数据解析:

void OneNet_RevPro(unsigned char *cmd)
{MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};								//协议包char *req_payload = NULL;char *cmdid_topic = NULL;unsigned short req_len = 0;unsigned char type = 0;short result = 0;char *dataPtr = NULL;char numBuf[10];int num = 0;cJSON *json , *json_value;cJSON *json1, *json_value1;cJSON *json2, *json_value2;type = MQTT_UnPacketRecv(cmd);switch(type){case MQTT_PKT_CMD:															//命令下发OLED_Refresh_Line("jinru111");result = MQTT_UnPacketCmd(cmd, &cmdid_topic, &req_payload, &req_len);	//解出topic和消息体if(result == 0){//打印收到的信息printf(  "cmdid: %s, req: %s, req_len: %d\r\n", cmdid_topic, req_payload, req_len);// 对数据包req_payload进行JSON格式解析json = cJSON_Parse(req_payload);if (!json)//如果json内容为空,则打印错误信息printf("Error before: [%s]\n",cJSON_GetErrorPtr());else{json_value = cJSON_GetObjectItem(json , "LED0");//提取对应属性的数值if((json_value->valueint)==1){GPIO_SetBits(GPIOB,GPIO_Pin_12);	}else if((json_value->valueint)==0)			GPIO_ResetBits(GPIOB,GPIO_Pin_12);	}//开关风扇json1 = cJSON_Parse(req_payload);if (!json1)printf("Error before: [%s]\n",cJSON_GetErrorPtr());else{json_value1 = cJSON_GetObjectItem(json1 , "feng");if((json_value1->valueint)==1)GPIO_SetBits(GPIOB,GPIO_Pin_5);	else if((json_value1->valueint)==0)GPIO_ResetBits(GPIOB,GPIO_Pin_5);	}//开关水泵json2 = cJSON_Parse(req_payload);if (!json2)printf("Error before: [%s]\n",cJSON_GetErrorPtr());else{json_value2 = cJSON_GetObjectItem(json2 , "shui");if((json_value2->valueint)==1){GPIO_SetBits(GPIOB,GPIO_Pin_6);	}else if((json_value2->valueint)==0)GPIO_ResetBits(GPIOB,GPIO_Pin_6);	}if(MQTT_PacketCmdResp(cmdid_topic, req_payload, &mqttPacket) == 0)	//命令回复组包{printf( "Tips:	Send CmdResp\r\n");ESP8266_SendData(mqttPacket._data, mqttPacket._len);			//回复命令MQTT_DeleteBuffer(&mqttPacket);									//删包}cJSON_Delete(json);//释放位于堆中cJSON结构体内存cJSON_Delete(json1);}break;case MQTT_PKT_PUBACK:														//发送Publish消息,平台回复的Ackif(MQTT_UnPacketPublishAck(cmd) == 0)//printf(  "Tips:	MQTT Publish Send OK\r\n");break;default:result = -1;break;}ESP8266_Clear();									//清空缓存if(result == -1)return;dataPtr = strchr(req_payload, ':');					//搜索'}'if(dataPtr != NULL && result != -1)					//如果找到了{dataPtr++;while(*dataPtr >= '0' && *dataPtr <= '9')		//判断是否是下发的命令控制数据{numBuf[num++] = *dataPtr++;}numBuf[num] = 0;num = atoi((const char *)numBuf);				//转为数值形式}if(type == MQTT_PKT_CMD || type == MQTT_PKT_PUBLISH){MQTT_FreeBuffer(cmdid_topic);MQTT_FreeBuffer(req_payload);}
}

2、传感器数据上云:

主函数中读取传感器数值,每隔一段时间上传:

		else if(timeCount >= 100)	//发送间隔{DHT11_Read_Data(&tempValue,&humidity);gas = AD_GetValue(ADC_Channel_2);ranqi = AD_GetValue(ADC_Channel_3);delay_ms(10);OneNet_SendData();//发送数据给onenetESP8266_Clear();	timeCount = 0;}

调用OneNet_SendData发送数据,在OneNet_SendData函数中又调用OneNet_FillBuf函数将要发送的数据拼接起来。

unsigned char OneNet_FillBuf(char *buf)
{char text[32];//LED0_FLAG=GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_12);//读取LED的开关状态(即对应引脚的)//LED1_FLAG=GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_13);memset(text, 0, sizeof(text));strcpy(buf, ",;");memset(text, 0, sizeof(text));sprintf(text, "Tempreture,%d;",tempValue);strcat(buf, text);memset(text, 0, sizeof(text));sprintf(text, "Humidity,%d;", humidity);strcat(buf, text);memset(text, 0, sizeof(text));sprintf(text, "tianranqi,%d;", gas);strcat(buf, text);memset(text, 0, sizeof(text));sprintf(text, "keranqiti,%d;", ranqi);strcat(buf, text);printf("buf_mqtt=%s\r\n",buf);return strlen(buf);}//==========================================================
//	函数名称:	OneNet_SendData
//
//	函数功能:	上传数据到平台
//
//	入口参数:	type:发送数据的格式
//
//	返回参数:	无
//
//	说明:		
//==========================================================
void OneNet_SendData(void)
{MQTT_PACKET_STRUCTURE mqttPacket = {NULL, 0, 0, 0};												//协议包char buf[128];short body_len = 0, i = 0;//printf( "Tips:	OneNet_SendData-MQTT\r\n");memset(buf, 0, sizeof(buf));//清空数组内容body_len = OneNet_FillBuf(buf);																	//获取当前需要发送的数据流的总长度if(body_len){if(MQTT_PacketSaveData(DEVID, body_len, NULL, 5, &mqttPacket) == 0)							数据点上传组包,将数据封装成mqtt协议所要求的数据包格式{{for(; i < body_len; i++)mqttPacket._data[mqttPacket._len++] = buf[i];ESP8266_SendData(mqttPacket._data, mqttPacket._len);									//上传数据到平台printf( "Send %d Bytes\r\n", mqttPacket._len);MQTT_DeleteBuffer(&mqttPacket);															//删包}else{printf(  "WARN:	EDP_NewBuffer Failed\r\n");}}}

五、微信小程序主要代码

在这里插入图片描述
图中圈起来的地方需要根据自己的数据进行填写,在下面的调试信息栏可以看到有数据上传,查看数据流即可:
在这里插入图片描述

1、index.js

主要是增加了控制风扇和水泵的代码:

feng_kai:function(){//按钮发送命令控制硬件wx.request({url:'https://api.heclouds.com/cmds?device_id=1108129261',header: {'content-type': 'application/json','api-key':'nV4Cso3uQMZR2EGQQiY49MRCfx8='},method: 'POST',data:{"feng":1},success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})
},feng_guan:function(){//按钮发送命令控制硬件wx.request({url:'https://api.heclouds.com/cmds?device_id=1108129261',header: {'content-type': 'application/json','api-key':'nV4Cso3uQMZR2EGQQiY49MRCfx8='},method: 'POST',data:{"feng":0},success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})
},shui_kai:function(){//按钮发送命令控制硬件wx.request({url:'https://api.heclouds.com/cmds?device_id=1108129261',header: {'content-type': 'application/json','api-key':'nV4Cso3uQMZR2EGQQiY49MRCfx8='},method: 'POST',data:{"shui":1},success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})
},shui_guan:function(){//按钮发送命令控制硬件wx.request({url:'https://api.heclouds.com/cmds?device_id=1108129261',header: {'content-type': 'application/json','api-key':'nV4Cso3uQMZR2EGQQiY49MRCfx8='},method: 'POST',data:{"shui":0},success(res){console.log("成功",res.data)},fail(res){console.log("失败",res)}})
},

需要注意的是这里的url需要更换成:‘https://api.heclouds.com/cmds?device_id=11081xxxxxx’,并且文件开头的apikey和设备号也要换成自己的。

2、index.wxml

最后加上:

<button type="primary" style="margin-top: 20px;" bindtap="feng_kai">开风扇</button>
<button type="warn" bindtap="feng_guan">关风扇</button><button type="primary" style="margin-top: 20px;" bindtap="shui_kai">开水泵</button>
<button type="warn" bindtap="shui_guan">关水泵</button>

六、源码获取

我用夸克网盘分享了「智能家居(MQTT+ONENET).rar」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
链接:https://pan.quark.cn/s/db251fd599bd
提取码:9sR9

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/439990.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java基于SpringBoot+Vue的网上超市管理系统

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

哪款笔记软件支持电脑和手机互通数据?

上班族在日常工作中&#xff0c;随手记录工作笔记已成为司空见惯的场景。例如&#xff1a;从快节奏的会议记录到灵感迸发的创意&#xff1b;跟踪项目进展&#xff0c;记录每个阶段的成果、问题和下一步计划&#xff1b;记录、更新工作任务清单等&#xff0c;工作笔记承载了职场…

echart 完整例子

<!--集团用电数据柱状图--> <template><div class"scsj-wsd"><div class"type-btns"><divclass"btns-item":class"currType 0 ? active : "click"change(0)">年</div><divclass&q…

从公有云对象存储迁移到回私有化 MinIO需要了解的所有信息

我们上一篇文章《如何从 AWS S3 遣返到 MinIO》的反响非常出色 - 我们已经接到了数十个企业的电话&#xff0c;要求我们提供遣返建议。我们已将这些回复汇总到这篇新文章中&#xff0c;其中我们更深入地研究了与遣返相关的成本和节省&#xff0c;以便您更轻松地进行自己的分析。…

重学Ajax

摘要&#xff1a;AJAX是一个在前端的应用非常广泛技术&#xff0c;为什么还要谈它呢&#xff1f;么得办法之前学的不全面&#xff0c;再收拾收拾。水平有限&#xff0c;欢迎指正&#xff01; AJAX&#xff08;全称&#xff1a;Asynchronous JavaScript and XML&#xff09;是一…

基于C#制作一个俄罗斯方块小游戏

目录 引言游戏背景介绍游戏规则游戏设计与实现开发环境与工具游戏界面设计游戏逻辑实现游戏优化和测试性能优化测试工具和流程说明引言 俄罗斯方块是一款经典的益智游戏,深受玩家喜爱。本文将介绍如何使用C#编程语言制作一个简单的俄罗斯方块小游戏,并探讨其设计与实现过程。…

Missing or invalid credentials.(Git push报错解决方案)

前言 本文主要讲解git push后报错Missing or invalid credentials的解决方案。这里针对的是windows的。 编程环境&#xff1a;VsCode 问题原因 问题翻译起来就是 凭据缺失或无效。这里我们解决方案是取消vscode里面默认的控制终端git凭据来解决,具体方案如下. 解决方案 1…

Vue3组件通信 详解(下)

Vue3组件通信 详解(上)-CSDN博客 v-model通讯 概述&#xff1a;实现 父↔子 之间相互通信。 v-model本质 组件标签上的v-model的本质&#xff1a;:moldeValue &#xff0b; update:modelValue事件。 <!-- 组件标签上使用v-model指令 --> <AtguiguInput v-model&qu…

中间件系列 - Kafka3.x从入门到精通

前言 学习视频&#xff1a;【尚硅谷】Kafka3.x教程&#xff08;从入门到调优&#xff0c;深入全面&#xff09;本内容仅用于个人学习笔记&#xff0c;如有侵扰&#xff0c;联系删除 1 Kafka 概述 1.1 定义 Kafka传统定义: Kafka 是一个分布式的基于发布/订阅模式的消息队列…

链表——超详细

一、无头单向非循环链表 1.结构&#xff08;两个部分&#xff09;&#xff1a; typedef int SLTDataType; typedef struct SListNode {SLTDataType data;//数据域struct SListNode* next;//指针域 }SLNode; 它只有一个数字域和一个指针域&#xff0c;里面数据域就是所存放的…

MySQL:MVCC原理详解

MySQL是允许多用户同时操作数据库的&#xff0c;那么就会出现多个事务的并发场景。那么再并发场景会出现很多问题&#xff1a;脏读、不可重复读、幻读的问题。 而解决这些问题所用到的方法就是&#xff1a;MVCC 多版本并发控制。而这个MVCC的实现是基于read_view、undoLog 如…

【基础算法练习】Trie 树

文章目录 模板题&#xff1a;[ACwing 835. Trie字符串统计](https://www.acwing.com/problem/content/description/837/)题目描述代码与解题思路 模板题&#xff1a;[ACwing 143. 最大异或对](https://www.acwing.com/problem/content/145/)题目描述代码与解题思路 Trie 算法需…