项目3 网关和APP 的MQTT 通信设计_第1页
项目3 网关和APP 的MQTT 通信设计_第2页
项目3 网关和APP 的MQTT 通信设计_第3页
项目3 网关和APP 的MQTT 通信设计_第4页
项目3 网关和APP 的MQTT 通信设计_第5页
已阅读5页,还剩136页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

2相关知识34任务小结与练习1任务实施任务引入与目标MQTT服务器部署一、任务引入与目标任务目标任务1以阿里云服务器为例,讲解在云服务器上通过开源EMQX软件搭建MQTT服务器的步骤。建议不要安装在本地(没有公网IP),而是安装在云服务器上。任务引入MQTT(消息队列遥测传输)是物联网中用于向设备发送消息和从设备中接收消息的轻量级消息传递协议,也是物联网系统设计中最主流和最受欢迎的协议。拥有1个可通过公网访问的MQTT服务器,就能很方便地让物联网网关、物联网APP、物联网后端等物联网客户端之间进行MQTT通信。二、相关知识MQTT组件物联网中使用的协议有很多种,以下是一些常用的物联网协议:(1)MQTT(MessageQueuingTelemetryTransport,消息队列遥测传输),是一种轻量级、灵活和可扩展的消息传输协议,适用于低带宽、高延迟或不可靠网络环境;(2)CoAP(ConstrainedApplicationProtocol,约束应用协议),是一种基于RESTful架构的应用层协议,适用于受限环境下的无线传感器网络和物联网设备通信;(3)HTTP(HypertextTransferProtocol,超文本传输协议),是一种广泛使用的应用层协议,适用于互联网上的客户端和服务器之间的通信,也可以用于物联网设备之间的通信。(4)DDS(DataDistributionService,数据分发服务),是一种面向数据的消息传输协议,适用于大规模分布式系统和实时应用场景;(5)ZigBee,是一种针对低功率无线传感器网络的通信协议,适用于自组织网络和低速率数据传输;(6)LoRaWAN(LongRangeWideAreaNetwork,长距离广域网),是一种长距离低功耗无线通信技术,适用于需要远程监测和控制的物联网场景。二、相关知识这些协议各有优劣,选择哪种协议取决于具体应用场景和需求。例如,如果需要在低带宽、高延迟或不可靠网络环境下传输数据,则MQTT可能是更好的选择;如果需要使用RESTful架构进行通信,则CoAP可能更适合;如果需要实时分布式数据传输,则DDS可能更合适。EMQXEMQX是一款全球下载量超千万的大规模分布式物联网MQTT服务器,单集群支持1亿物联网设备连接,消息分发时延低于1毫秒,为高可靠、高性能的物联网实时数据移动、处理和集成提供动力,助力企业构建关键业务的IoT平台与应用。EMQX自2013年在GitHub发布开源版本以来,获得了来自50多个国家和地区的20000余家企业用户的广泛认可,累计连接物联网关键设备超过1亿台。二、相关知识我们可通过EMQX在云服务器上部署MQTT服务器。你知道有哪些云服务器提供商吗?课堂讨论学思之窗阿里云是阿里巴巴集团旗下的云计算服务品牌,提供包括计算、存储、网络、安全、大数据等多种云计算产品及解决方案。阿里云在全球范围内拥有众多数据中心和节点,可以为用户提供高性能、高可用、高可靠的云计算服务。在日常学习和工作中,要实践和运用像阿里云这样的世界领先的云计算产品和服务,按照党的二十大报告提出的“必须坚持创新是第一动力,深入实施创新驱动发展战略”要求,参与推进“双创”“众创”等创新活动,为国家创新能力提升做出贡献。相关链接EMQX开源版文档:www.emqx.io/docs/zh/latest/。EMQX官网:/zh。三、任务实施实施设备安装了CentOS操作系统的计算机(最好是云服务器)。实施过程EMQX安装登录官网(/zh/downloads?product=broker),选择开源版。选择系统对应的合适版本,如图3-1所示。图3-1选择对应的操作系统三、任务实施CPU架构具体看自己电脑的CPU情况,示例中为x86_64(intel)架构,如图3-2所示。按提示命令执行即可。注意如果在linux的home下安装,可以找到文件夹emqx,通过cdemqx进入,进而找到bin文件夹,执行即可。其中下载安装包的代码如下:EMQX启动说明文档:/broker/v4.3/getting-started/start.html。wget/zh/downloads/broker/4.2.14/emqx-centos7-4.2.14-x86_64.zip相关链接图3-2选择对应的CPU架构三、任务实施2.阿里云的EMQX配置(1)开放端口。在虚拟机安装的Linux使用该方式放开端口:保存操作:iptables-AINPUT-ptcp--dport1883-jACCEPTiptables-AINPUT-ptcp--dport8883-jACCEPTiptables-AINPUT-ptcp--dport8083-jACCEPTiptables-AINPUT-ptcp--dport8080-jACCEPTiptables-AINPUT-ptcp--dport18083-jACCEPTserviceiptablessave在阿里云对应的云服务器的安全组中添加对应的开放端口,18083对应控制台,如图3-3所示。图3-3阿里云服务器开放端口三、任务实施(2)开启emqx。通过命令行开启,需要进入bin目录的emqx打开,如图3-4所示。(3)访问EMQX后台。访问后台地址:http://localhost:18083。其中,localhost可以替换为你的云服务器公网IP或者虚拟机IP。图3-4开启EMQX三、任务实施3.配置EMQX服务器用户名/密码方式登录(1)完整代码。共分为3步:[root@iZbp1j4preny574qlep0klZemqx]#./bin/emqxstopok[root@iZbp1j4preny574qlep0klZemqx]#vim./etc/emqx.conf[root@iZbp1j4preny574qlep0klZemqx]#./bin/emqxstartEMQXBroker4.2.14isstartedsuccessfully![root@iZbp1j4preny574qlep0klZemqx]#(2)步骤1:停止服务。./bin/emqxstop(3)编辑用户名、密码配置文件。通过语句vim./etc/plugins/emqx_auth_username.conf进入配置文件,然后在文件中增加用户名、密码,密码算法改为plain(透传),如图3-5所示。三、任务实施Linux中,修改、删除指令分别为shift+“i”、shift+“x”。保存操作指令为shift+“:”,然后输入“wq!”退出。图3-5编辑用户名、密码配置文件(4)关闭匿名登录。vim./etc/emqx.conf查找allow_anonymous,修改为false。注意:如果想开放给别人匿名登录,要再把false改为true。四、任务小结与练习任务小结任务1学习了如何在一台安装了CentOS操作系统的云服务器上,通过EMQX部署MQTT服务器的过程。如果没有云服务器资源,则可以直接使用作者搭建的MQTT服务器,IP地址为69,端口为1883,各个MQTT客户端不需要密码即可访问。也可以在本地Windows操作系统的计算机上,创建Linux镜像,然后利用EMQX部署,只是因为没有公网IP,所以只适合局域网内的计算机,使用不太方便。根据自己的资源情况,部署一个MQTT服务器。实践练习谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标MQTT.fx客户端测试MQTT通信一、任务引入与目标任务目标在任务2中,我们将安装MQTT.fx测试软件,创建MQTT客户端,观察理解MQTT客户端和MQTT代理服务器之间的通信过程。如果任务1中因为资源问题不方便搭建自己的MQTT服务器,那么可以使用作者搭建好的MQTT服务器,其IP地址为69,端口为1883,各个MQTT客户端不需要密码即可访问。任务引入众所周知,MQTT是物联网中非常重要的一种通信协议。任务1介绍了MQTT服务器的搭建步骤,那么到底MQTT是如何通信的呢?二、相关知识什么是MQTTMQTT(消息队列遥测传输)是物联网中用于向设备发送消息和从设备接收消息的轻量级消息传递协议,通过TCP/IP网络运行。MQTT由于其简单性和易用性而迅速成为最受欢迎的物联网协议。MQTT的最新版本是v5,但v3.1.1和v3.1仍然是最常用的。MQTT组件MQTT通过发布/订阅模型工作,如图3-6所示。MQTT设置有2个主要组件:代理Broker,是一个中央集线器或服务器,负责客户端之间的所有连接并存储所有消息;客户端,是连接到代理并可以发布和接收消息的设备。图3-6MQTT的发布/订阅模型二、相关知识MQTT消息是如何传递的准备工作(以客户端A发送消息给客户端B为例):首先双方确定好消息主题名(如topic1)和消息载荷格式;然后,客户端A通过client.connect()方法登录MQTT代理服务器;最后,客户端B通过client.connect()方法登录MQTT代理服务器,并通过client.subscribe()方法订阅消息主题,通过client.setCallback()方法设置回调函数。传递过程:客户端A通过client.publish()方法发送主题为topic1的消息到MQTT代理服务器,代理会转发消息到所有订阅了此消息的客户端;客户端B收到消息后,在回调函数中对消息进行解析处理。MQTT协议中的一些关键词和基本概念订阅(Subscribe):订阅包含主题名、服务质量(Qos)等级。主题名(TopicName):附加在应用消息上的一个标签。服务器(Broker):在消息订阅模型中充当服务器的角色,类似于送信的邮差。消息服务质量(Qos)机制:通过使用Qos机制,来保证通信的质量。载荷(Payload):消息订阅者所具体接收的内容。客户端ID:MQTT客户端的唯一标识,注意一定不能和其他客户端重名,否则会造成冲突。三、任务实施实施设备安装了Windows操作系统的计算机,部署了MQTT服务器的云服务器。实施过程1.安装MQTT.fx软件网址为http://www.jensd.de/apps/mqttfx/1.7.1/,下载后双击安装,界面如图3-7所示。图3-7MQTT.fx软件界面三、任务实施MQTT.fx客户端既可以作为发布端(Publish),也可以作为接收端(Subscribe),利用MQTT服务器进行消息的中转。众所周知,如果客户端A和B都登录了EMQX服务器,客户端B订阅了主题(topic)为X的消息,那么客户端A发布消息X后,客户端B就会收到此消息。2.MQTT.fx客户端连接MQTT服务器如图3-8所示,设置客户端ID、登录账号密码、要连接的MQTT服务器。设置路径为:Extras→EditConnectionProfiles。图3-8MQTT.fx设置连接客户端ID需要独一无二,可以用手机号、qq号、学号等测试。因为图中的MQTT服务器未设置登录密码,MQTT客户端可以公开访问,所以用户名和密码暂空。三、任务实施设置完毕,点击确定。回到主页面,选择对应的MQTT服务器,然后点击Connect进行连接,如图3-9所示。3.MQTT.fx客户端发布消息如图3-10所示,在Publish栏中,输入要发布的消息topic和消息内容,点击“Publish”按钮即可发布成功。如果有其他客户端订阅了这个topic的消息,就会收到。图3-9点击Connect连接MQTT服务器可以在MQTT服务器的后台查看客户端连接情况。图3-10发送MQTT消息三、任务实施4.MQTT.fx客户端订阅与接收消息在Subscribe栏中,输入要订阅的消息topic,点击“Subscribe”按钮即可订阅成功,如图3-11所示。如果有其他客户端发送这个topic的消息,内容就会显示在右侧。可以在两个客户端之间验证收发过程。如图3-10所示发布消息后,MQTT.fx客户端可以收到消息,接收效果如图3-12所示。图3-11订阅MQTT消息图3-12接收MQTT消息四、任务小结与练习任务小结在任务2中,我们安装了MQTT.fx软件,创建了MQTT客户端并通过实际操作,观察了MQTT客户端和MQTT代理服务器之间的通信过程。自定义发布和订阅的消息主题(必须一样才行),在MQTT.fx客户端测试MQTT消息的收发。实践练习谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标物联网APP的MQTT配置一、任务引入与目标任务目标任务3在AndroidStudio工程中对MQTT通信功能进行配置,包括网络权限的配置和导入MQTT的jar包,为后续APP和其他MQTT客户端之间的MQTT通信做准备。任务引入任务2测试了MQTT.fx客户端的MQTT通信,包括发布消息和订阅与接收消息。其实,不同的MQTT客户端的MQTT通信过程都是一样的。二、相关知识命名规范类和接口名:采用大驼峰命名法(PascalCase),即每个单词首字母大写,不使用下划线或其他特殊字符。方法和变量名:采用小驼峰命名法(CamelCase),即第一个单词小写,后面的每个单词首字母大写。常量名:全部使用大写字母,并使用下划线分隔单词。格式规范缩进:使用4个空格进行缩进。括号:左花括号({)应该与声明语句放在同一行,右花括号(})应该独占一行。注释:为了提高代码的可读性和可维护性,应在关键的代码块前面添加注释。在Android开发中,编码规范是非常重要的,包括命名、格式、注释等多个方面。二、相关知识注释规范文件头注释:每个Java文件都应该有一个头部注释,包括作者、创建日期和版本信息等。类注释:每个类都应该有一个类注释,说明该类的作用和设计思路。方法注释:每个方法都应该有一个方法注释,说明该方法的功能、参数和返回值等。需要注意的是,这些规范只是一些建议,具体实现应该根据团队和项目的要求而定。但是,遵循这些规范可以使代码更加清晰,易于理解和维护。三、任务实施实施设备安装了AndroidStudio开发环境的计算机。实施过程1.添加网络权限如图3-13所示,允许程序打开网络套接字,在src→main→AndroidManifest.xml文件中的对应位置编写以下代码:<uses-permissionandroid:name="android.permission.INTERNET"/>图3-13添加网络权限三、任务实施2.导入MQTT的jar包下载org.eclipse.paho.client.mqttv3-1.2.0.jar,粘贴到libs目录下,如图3-14所示。图3-14导入MQTT的jar包选中新放入工程目录的jar包,右键选择并点击“addaslibrary”,即可保证jar包的依赖关系。接下来就可以使用jar包的相关函数创建MQTT客户端,以及进行MQTT通信。三、任务实施3.测试完成以上步骤,在代码里输入“Mqtt”,相关的方法就有了,如图3-15所示。如果没有,则看看是不是没有同步,或者将Andoid工程重启一下。注意:MQTT通信相关的类名以“Mqtt”开头,采用大驼峰命名法,首字母大写。图3-15测试MQTT是否配置成功打开项目根目录下的settings.gradle文件,修改文件中的rootP="新项目名",如图3-16所示,然后点击同步。图3-16修改项目名三、任务实施修改路径文件夹名:关闭AndroidStudio,找到工程所在路径,修改所在路径的文件夹为新的名称。打开AndroidStudio,重新导入工程即可。如果想要修改后的工程与之前的工程不冲突(实现不覆盖安装),还需要修改build.gradle文件的applicationId,然后同步即可,如图3-17所示。图3-17修改applicationId图3-18修改app_name的值如果要更改APP名称,可在app→src→main→res→values→strings.xml中修改app_name的值,如图3-18所示。四、任务小结与练习任务小结任务3完成了物联网APP的MQTT相关配置,就可以在Android工程中使用MQTT相关的基础方法了,如执行连接、订阅消息、发布消息。修改APP名称,加上学号。实践练习谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标物联网APP的MQTT变量与函数一、任务引入与目标任务目标任务4介绍MQTT需要定义的变量,并在MQTT方法的基础上,编写初始化、连接、重连接、发布消息、关闭连接函数。使用的Activity文件为SecondActivity.java,通信时需要使用Handler实现消息的传递。任务引入APP的页面2使用MQTT通信,包括通过APP发送MQTT消息(控制命令),以及接收MQTT消息并显示。任务3通过MQTT的配置,已经可以在Android工程中使用MQTT相关的基础方法了,如执行连接、订阅消息、发布消息。因为是网络通信,所以MQTT现有的方法还需要考虑各种异常的处理,才能够正常使用。二、相关知识为什么需要Handler类当多个线程并发操作UI组件,可能导致线程不安全,故Android并不允许在UI线程(主线程)外操作UI。正确的做法是:Android应用启动后默认开启一个主线程;如果其他子线程要更新UI,可以将要更新的内容通过Handler传递给主线程,在主线程中完成UI更新。Handler执行流程如图3-19所示,Handler执行流程如下:首先,在主线程中直接创建Handler对象;然后,子线程想修改Activity中的UI组件时,可以通过Handler对象向主线程发送消息;最后,发送的消息会先到主线程的MessageQueue(消息队列)等待,由Looper按先入先出顺序取出,再由Handler根据message对象的what属性对应进行处理。图3-19Handler执行流程二、相关知识课堂讨论Android并不允许我们在UI线程外操作UI,如果尝试的话,能够成功吗?三、任务实施实施设备安装了AndroidStudio开发环境的计算机,部署了MQTT服务器的云服务器。1.变量与对象在SecondActivity.java中定义以下变量与对象:ActivitySecondBindingbinding2;//创建activity_second布局类对象privateStringhost="tcp://69:1883";//EMQX物联网服务器privateStringusername="user";//EMQX服务器未设MQTT客户端登录密码,所以可以空着;假如设置了客户端访问的账号密码,就必须输入privateStringpassword="";privateStringmqtt_id=;//独一无二的,可以用手机号、qq号等privateStringmqtt_sub_topic="my_FX/post";//:/手机号/my_FX/post,代表MQTT.fx上报的消息privateStringmqtt_pub_topic="my_APP/set";//:/手机号/my_APP/set,代表APP发布的命令privateintLedStatus=0;//APP发布的消息为{"LedStatus":0},{"LedStatus":1},将用于控制网关所接Led实施过程三、任务实施privateintLedStatus=0;//APP发布的消息为{"LedStatus":0},{"LedStatus":1},将用于控制网关所接LedprivateScheduledExecutorServicescheduler;privateMqttClientclient;privateMqttConnectOptionsoptions;//MQTT连接时的参数privateHandlerhandler;其中定义了MQTT服务器IP地址、服务器端口号、客户端用户名,客户端登录密码、客户端ID、客户端发布消息主题、客户端订阅消息主题等。注意:创建的MQTT客户端ID不能和其他MQTT客户端ID冲突。以上代码还创建了binding、调度器、MQTT客户端、MQTT参数、Handler等对象。三、任务实施2.函数onCreate函数后面复制5个函数。(1)初始化函数。//1-Mqtt初始化函数privatevoidMqtt_init(){try{//host主机名,clientid连接MQTT的客户端ID,MemoryPersistence设置clientid保存形式,默认以内存保存client=newMqttClient(host,mqtt_id,newMemoryPersistence());//MQTT的连接设置options=newMqttConnectOptions();//设置是否清空session,false表示服务器会保留客户端连接记录,true表示每次都以新身份连接服务器options.setCleanSession(false);//设置连接的用户名options.setUserName(username);//设置连接密码options.setPassword(password.toCharArray());//设置超时时间,单位为秒options.setConnectionTimeout(10);三、任务实施//设置会话心跳时间options.setKeepAliveInterval(60);//设置回调client.setCallback(newMqttCallback(){@OverridepublicvoidconnectionLost(Throwablethrowable){//连接丢失后,一般在这里进行重新连接System.out.println("ConnectionLost");//startReconnect();}@OverridepublicvoiddeliveryComplete(IMqttDeliveryTokeniMqttDeliveryToken){//publish后会执行到这里System.out.println("deliveryComplete"+iMqttDeliveryToken.isComplete());}@OverridepublicvoidmessageArrived(Strings,MqttMessagemqttMessage)throwsException{//subscribe后得到的消息会执行到这里面System.out.println("MessageArrived");Messagemsg=newMessage();msg.what=3;//收到消息标志位msg.obj=s+""+mqttMessage.toString();handler.sendMessage(msg);//hander回传}});}catch(Exceptione){e.printStackTrace();}}三、任务实施通过初始化函数,完成MQTT的初始化。例如:将MQTT客户端client实例化,设置MQTT连接的参数options,通过setCallback方法设置回调。回调中最关键的是messageArrived函数。当MQTT客户端client收到订阅的消息后,会将消息的主题、内容拼接在一起作为obj,再增加标志位what,回传给UI线程的handler对象,handler处理后可以用于更新UI。//2-Mqtt初始化函数privatevoidMqtt_connect(){newThread(newRunnable(){@Overridepublicvoidrun(){try{if(!(client.isConnected())){//如果还未连接client.connect(options);Messagemsg=newMessage();msg.what=31;handler.sendMessage(msg);}(2)连接函数。三、任务实施因为连接网络耗时,所以需要开启子线程。MQTT连接函数是在重连接函数中被调用的。如果连接成功,那么回传给handler的标志位what为31;如果连接失败,那么回传给handler的标志位what为30。UI线程的handler处理后可以用于更新UI。}catch(Exceptione){e.printStackTrace();Messagemsg=newMessage();msg.what=30;handler.sendMessage(msg);}}}).start();}三、任务实施(3)重连接函数。//3-MQTT重连privatevoidstartReconnect(){scheduler=Executors.newSingleThreadScheduledExecutor();scheduler.scheduleAtFixedRate(newRunnable(){@Overridepublicvoidrun(){if(!client.isConnected()){Mqtt_connect();}}},0*1000,10*1000,TimeUnit.MILLISECONDS);}在重连接函数中,实现了一个定时任务,该任务会在一次任务执行完毕的间隔时间后,才会执行下一次任务。任务就是调用连接函数,实现客户端对MQTT服务器的连接。三、任务实施(4)发布消息函数。//4-MQTT重连privatevoidpublishmessageplus(Stringtopic,Stringmessage2){if(client==null||!client.isConnected()){return;}MqttMessagemessage=newMqttMessage();message.setPayload(message2.getBytes());try{client.publish(topic,message);}catch(MqttExceptione){e.printStackTrace();}}publishmessageplus函数会调用client对象的publish方法,发布一条消息到MQTT服务器。publishmessageplus函数的第一个参数是消息topic(主题),第二个参数是消息的payload(载荷)。MQTT服务器收到消息后,会转发消息给所有订阅了消息topic的MQTT客户端。三、任务实施(5)关闭连接函数。//5-MQTT重连publicvoiddisconnect(){try{if(client!=null){if(client.isConnected())client.unsubscribe(mqtt_sub_topic);client.disconnect();client.close();client=null;}}catch(Exceptione){e.printStackTrace();}}在关闭连接函数中,分为3步:取消订阅,断开连接,关闭客户端。三、任务实施3.OnCreate方法(1)调用初始化和重连接函数。在OnCreate方法中,调用MQTT初始化和重连接函数,如图3-20所示。图3-20调用MQTT初始化和重连接函数图3-21调用disconnect()函数跳转到下一页时,如果MQTT客户端还在连接的话,需要释放掉资源,可以在btn21的事件监听中调用disconnect()函数实现,如图3-21所示。三、任务实施(2)Handler处理。对象handler是在UI线程创建的,重写了处理消息的方法:handleMessage。处理时,根据message对象的what属性值分别进行处理:①如果回传的标志位是3(收到订阅消息),则在屏幕上Toast消息内容(UI刷新);②如果回传的标志位是30(连接失败),则在屏幕上Toast“连接失败”(UI刷新);③如果回传的标志位是31(连接成功),则在屏幕上Toast“连接成功”(UI刷新)。代码如下:handler=newHandler(){@SuppressLint("SetTextI18n")publicvoidhandleMessage(Messagemsg){super.handleMessage(msg);switch(msg.what){case1://开机校验更新回传,未用到break;case2://反馈回传,未用到break;三、任务实施case3://MQTT收到消息回传Toast.makeText(SecondActivity.this,msg.obj.toString(),Toast.LENGTH_SHORT).show();break;case30://连接失败Toast.makeText(SecondActivity.this,"连接失败",Toast.LENGTH_LONG).show();break;case31://连接成功Toast.makeText(SecondActivity.this,"连接成功",Toast.LENGTH_LONG).show();break;default:break;}}};三、任务实施4.运行结果如图3-22所示,当进入page2页面时,会显示连接成功。图3-22显示MQTT连接成功将显示连接成功的界面截图上传到课程学习平台。在SecondActivity.java中进行页面跳转时,不调用disconnect()函数。观察从page2跳转到page3,再跳转回page2后,Toast的内容是什么,并分析原因。四、任务小结与练习任务小结任务3完成了物联网APP的MQTT相关配置,就可以在Android工程中使用MQTT相关的基础方法了,如执行连接、订阅消息、发布消息。修改APP名称,加上学号。实践练习谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标物联网APP和MQTT.fx客户端通信一、任务引入与目标任务目标任务5使用MQTT.fx软件创建一个MQTT客户端,让APP和其进行MQTT通信,实现如下功能:(1)APP发送,MQTT.fx接收,消息topic为“/手机号/my_APP/set”,代表APP发布的命令;(2)MQTT.fx发送,APP接收,消息topic为“/手机号/my_FX/post”,代表MQTT.fx发布的消息。APP和MQTT.fx这两个客户端需要通过MQTT服务器进行消息转发。任务引入任务4中APP已经连接到MQTT服务器,MQTT服务器起到了消息代理的作用。如果APP和另一个MQTT客户端之间能进行消息传递,感受会更直观。二、相关知识Java中的字符串处理方法在Java中,常用的字符串(String类)处理函数有indexOf()方法、substring()方法、contains()方法,结合起来可以用于字符串的解析。indexOf()方法indexOf()方法可以在字符串中查找子字符串出现的位置(即索引值)。如果存在则返回索引值,如果不存在则返回-1。其中,字符串的索引是从0开始的。substring()方法substring()方法用于截取字符串的子字符串。其语法为:publicStringsubstring(intbeginIndex),或publicStringsubstring(intbeginIndex,intendIndex)。参数:beginIndex———起始索引(包括),索引从0开始;endIndex———结束索引(不包括)。二、相关知识contains()方法contains()方法用于判断字符串中是否包含指定的字符或子字符串。其语法为:publicbooleancontains(CharSequencechars)。参数:chars———要判断的字符或字符串。返回值:如果包含指定的字符或字符串,则返回true,否则返回false。课堂讨论根据介绍,indexOf()方法是否可以起到contains()方法同样的功能,即判断字符串的包含关系?三、任务实施实施设备安装了AndroidStudio开发环境和MQTT.fx软件的计算机,部署了MQTT服务器的云服务器。1.MQTT.fx配置MQTT.fx可通过点击齿轮图标或从Extras→EditConnectionProfiles进入连接配置。如图3-23所示,在连接配置中,设置要访问的MQTT代理服务器IP地址和端口号,端口号为1883;设置独一无二的客户端ID,也可以点击“Generate”自动生成;其他参数可以默认,访问MQTT服务器的账号、密码可以空着。实施过程图3-23MQTT.fx配置三、任务实施点击“Connect”后,在MQTT.fx中创建的MQTT客户端即可建立与MQTT服务器的连接。如图3-24所示,点击“Publish”选项卡,可以设置发布消息的topic,注意这个topic是APP要收到的消息topic。图3-24MQTT.fx发布消息图3-25MQTT.fx订阅消息如图3-25所示,点击“Subscribe”选项卡,可以设置订阅消息的topic,点击Subscribe即可订阅成功。注意这个topic是APP要发布的消息topic。三、任务实施2.APP程序设计(1)APP的MQTT消息约定。在APP中,布局如图3-26所示,约定如下:①点击image21和image22,发布消息。topic为“/手机号/my_APP/set”,payload分别为{"LedStatus":1}和{"LedStatus":0};②收到订阅的消息,topic为“/手机号/my_FX/post”,提取消息payload的“temperature”字段的值,拼接后显示在text23处。消息payload格式为{"temperature":16}。发布和接受的消息都是字符串类型,毫无疑问我们要求消息满足JSON格式规范(这是基本要求,必须遵守)。图3-26image21和image22的布局三、任务实施(2)APP发布MQTT消息。如图3-27所示,需要在image21和image22的单击事件监听器中调用消息发布函数。代码如下:图3-27image21和image22的单击事件监听//点击image21,发布消息:{"LedStatus":1}binding2.image21.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewview){publishmessageplus(mqtt_pub_topic,"{\"LedStatus\":1}");}});//点击image22,发布消息:{"LedStatus":0}binding2.image22.setOnClickListener(newView.OnClickListener(){@OverridepublicvoidonClick(Viewview){publishmessageplus(mqtt_pub_topic,"{\"LedStatus\":0}");}});三、任务实施点击image21,调用自编的publishmessageplus函数发布MQTT消息,payload为{"LedStatus":1};点击image22,调用自编的publishmessageplus函数发布MQTT消息,payload为{"LedStatus":0}。点击这两个图像控件,发布的MQTT消息topic是一样的。case31://连接成功Toast.makeText(MainActivity.this,"连接成功",Toast.LENGTH_LONG).show();try{//订阅消息client.subscribe(mqtt_sub_topic,1);}catch(MqttExceptione){e.printStackTrace();}break;(3)APP接收MQTT消息。接收消息需要注意,先订阅消息,然后才能接收(MQTT服务器转发过来的消息)。下面在Handler中完成这两步。当APP的MQTT客户端client连接MQTT服务器成功后,调用subscribe方法订阅消息。代码如下:三、任务实施接收解析的代码如下:case3://MQTT收到消息回传if(msg.obj.toString().contains("temperature")){StringT_val=msg.obj.toString().substring(msg.obj.toString().indexOf("temperature")+13,msg.obj.toString().indexOf("}"));Stringtext_val="温度:"+T_val+"℃";binding2.text23.setText(text_val);}break;分析当APP收到订阅消息后,是如何提取出温度值,并在text23文本框中显示的:已知回传Handler消息标志为3,obj为/1**********/my_FX/post:{"temperature":16};Handler处理时,判断标志是否为3,然后调用toString()方法将msg.obj转换为字符串,再调用contains方法判断是否包含子字符串"temperature";假如以上均满足,在字符串中进行截取操作,起始位置是字符"t"的位置加13,定位到温度的数值部分,结束位置是字符右花括号(不包括),这样就提取出了子字符串"16"。最后和前后字符串拼接后,在text23显示出来"温度:16℃"。三、任务实施3.APP和MQTT.fx通信测试(1)APP发送MQTT消息到MQTT.fx。如图3-28所示,当在APP上点击image21后,可在MQTT.fx客户端的Subscribe选项卡看到消息内容。图3-28MQTT.fx收到image21的消息点击image22,MQTT.fx客户端也可以成功收到APP发送的MQTT消息,如图3-29所示。图3-29MQTT.fx收到image22的消息三、任务实施(2)MQTT.fx发送MQTT消息到APP。如图3-30所示,当MQTT.fx发布消息时,APP可以收到并解析显示。还可以在真机上测试,效果是一样的。图3-30MQTT.fx发送MQTT消息到APP四、任务小结与练习任务小结任务5学习了两个MQTT客户端之间如何进行通信。接下来就可以设计网关程序,实现网关和APP之间的MQTT通信,比如获取网关上报的各种传感数据,或者控制网关所接的执行器。让MQTT.fx客户端发送MQTT消息,payload格式为{"humidity":43},APP接收后解析展示“humidity”字段的值。实践练习谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标物联网APP显示温湿度一、任务引入与目标任务目标ESP32上报:通过DHT11传感器监测温湿度值,MQTT消息topic="/手机号/my_ESP32/post",MQTT消息payload="{"temperature":16}",或者"{"humidity":43}"。APP收到后,将温度值解析后显示在text21中,将湿度值解析后显示在text22中。任务6分解为2个环节:网关数据上报、APP设计。第一个环节是在Arduino环境下编写DHT11相关库的检测函数,再调用客户端的publish方法;第二个环节是将任务5的MQTT.fx客户端ID换成ESP32客户端ID,解析后更新UI控件,从text23改为text21和text22。任务引入任务5让MQTT.fx客户端发送包含虚拟传感器值的MQTT消息,由APP订阅、接收、解析并展示。本任务让ESP32网关连接真实的传感器,检测温湿度并上报,由APP订阅、接收、解析并展示,构建一个温湿度的远程监控系统。二、相关知识DHT11传感器简介DHT11传感器是一款含有已校准数字信号输出的温湿度传感器,应用数字模块采集技术和温湿度传感技术,确保产品具有极高的可靠性和工作稳定性。传感器包括一个电阻式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连。DHT11采用单线制串行接口,使系统集成变得简易快捷,节约硬件资源。产品为4针单排引脚封装,连接方便。课堂讨论你还知道有哪些单总线的传感器?二、相关知识DHT11传感器应用电路VCC供电电压的范围为3~5.5V,GND接地。DATA为单串行数据总线,可和单片机的数据引脚相连,如图3-31所示。注意:数据引脚需要完成输入和输出双向传输,故引脚的工作模式在初始化时不必设置,而是在检测时按照时序配置引脚的工作模式。图3-31DHT11传感器应用电路二、相关知识DFRobot_DHT11库用户通过外设库的封装,可以较为方便地使用相关外设,而不需要关心复杂的配置和时序知识。用户可在Arduino开发环境中调用DFRobot_DHT11库,使用DHT11传感器。项目1已经将DFRobot_DHT11外设库下载到Arduino安装目录的libraries文件夹中,在Arduino工程中,用户通过以下语句即可调用:#include"DFRobot_DHT11.h"其他关键语句如下:DFRobot_DHT11DHT;//创建温湿度传感器对象DHTDHT.read(DHT11_PIN);//DHT对象调用read方法,完成一次温湿度检测DHT检测温湿度后,温度值和湿度值会分别赋值给DHT对象的temperature属性和humidity属性。三、任务实施实施设备ESP32网关和DHT11温湿度传感器各一个,杜邦线若干,安装了Arduino开发环境和AndroidStudio开发环境的计算机,部署了MQTT服务器的云服务器。1.网关与传感器硬件连接DHT11_DAT———ESP32_IO26DHT11_GND———ESP32_GNDDHT11_VCC———ESP32_VCCDHT11的单数据总线接ESP32的Pin26。实施过程三、任务实施2.网关程序设计(1)头文件、宏、变量、对象定义。#include<WiFi.h>#include<PubSubClient.h>#include<ArduinoJson.h>//需要加载ArduinoJson和DFRobot_DHT11库,否则报错#include"DFRobot_DHT11.h"#defineDHT11_PIN26/*配置WIFI名和密码*/constchar*WIFI_SSID/="YYY_11_101";constchar*WIFI_PASSWORD="lxy413026";/*配置域名和端口号*/constchar*mqtt_server="69";constuint16_tPORT=1883;constchar*mqtt_id=ESP";constchar*mqtt_username="";constchar*mqtt_password="";/*需要操作的产品标识符(温度、湿度)*/StringTempIdentifier="temperature";StringHumiIdentifier="humidity";/*需要上报和订阅的TOPIC*/constchar*pubTopic="my_ESP32/post";//******发布WiFiClientespClient;PubSubClientclient(espClient);//创建了MQTT客户端,即ESP32硬件DFRobot_DHT11DHT;三、任务实施程序中:①调用了WiFi库、PubSubClient库(用于创建MQTT客户端)、ArduinoJson库(用于JSON解析)、DFRobot_DHT11(用于DHT11温湿度传感器);②定义了DHT11的数据引脚、配置了WiFi通信时的账号密码、MQTT服务器的IP地址和端口号、MQTT客户端ID、客户端访问服务器时的用户名和密码;③定义了JSON对象(上报的消息载荷)里的温度和湿度字段、要发布的消息topic;④创建了WiFi客户端,进一步创建了MQTT客户端对象client,并创建了温湿度传感器对象DHT。三、任务实施voidsetup(){Serial.begin(115200);connectWiFi();client.setServer(mqtt_server,PORT);//没有提供用户名和密码,因为EMQX服务器允许公开访问,如果设置的话是需要提供的/*设置回调函数,当收到订阅信息时会执行回调函数*/client.setCallback(callback);/*连接到MQTT服务器*/reconnect();}(2)初始化函数。初始化函数中:设置串口0的波特率为115200,对应的电脑串口调试助手波特率要一致;进行WiFi连接;设置MQTT客户端要访问的MQTT服务器;设置MQTT客户端收到消息后的回调处理函数,并连接到MQTT服务器。三、任务实施voidreconnect(){while(!client.connected()){Serial.print("AttemptingMQTTconnection...");if(client.connect(mqtt_id,mqtt_username,mqtt_password)){Serial.println("connected");}else{Serial.print("failed,rc=");Serial.print(client.state());Serial.println("tryagainin5seconds");delay(5000);}}}(3)reconnect函数。在reconnect函数中,client对象会调用connected方法判断是否连接到MQTT服务器;如果未连接,会尝试调用connect方法进行连接;如果尝试连接失败,间隔一段时间后会再次调用connect方法进行连接。循环是通过While语句实现的。三、任务实施uint8_ttempTime=0;voidloop(){if(!client.connected()){reconnect();}/*两分钟上报两次温湿度信息*/if(tempTime>240){tempTime=0;DHT.read(DHT11_PIN);Serial.print("DHT.temperature=");Serial.println(DHT.temperature);Serial.print("DHT.humidity=");Serial.println(DHT.humidity);client.publish(pubTopic,("{\""+TempIdentifier+"\":"+DHT.temperature+"}").c_str());}else{tempTime++;delay(500);}client.loop();}(4)loop函数。loop函数中,MQTT客户端每2分钟上报一次消息,消息的topic="/手机号/my_ESP32/post"。假如采集到的温度值是16℃,消息载荷="{"temperature":16}"。程序中,DHT对象通过read方法检测温湿度,温度值和湿度值会分别赋值给DHT对象的temperature属性和humidity属性。三、任务实施为什么是每隔2分钟上报一次MQTT消息?如果想修改间隔时间为3分钟,有哪些办法?消息中的“\”是什么意思,有什么作用?课堂讨论3.APP设计(1)消息topic。如图3-32所示,APP是作为接收消息的MQTT客户端使用的,只要修改一下订阅的消息topic就可以了,即将"/手机号/my_FX/post"修改为"/手机号/my_ESP32/post",至于发布和订阅消息的内容,都保持不变。图3-32修改订阅的消息topic三、任务实施(2)消息payload解析。APP的MQTT客户端收到消息后,通过Handler回传到UI线程处理,原来是解析后展示在tet23,现在修改为解析温度展示在text21文本框中。代码如下:case3://MQTT收到消息回传if(msg.obj.toString().contains("temperature")){StringT_val=msg.obj.toString().substring(msg.obj.toString().indexOf("temperature")+13,msg.obj.toString().indexOf("}"));Stringtext_val=T_val+"℃";binding2.text21.setText(text_val);}//Toast.makeText(SecondActivity.this,msg.obj.toString(),Toast.LENGTH_SHORT).show();break;三、任务实施4.结果展示上传程序,打开Arduino开发环境的串口监视器,会显示连接MQTT服务器成功。然后观察温湿度检测结果,如图3-33所示。对应的,如图3-34所示,在虚拟手机上可以看到温度值,和串口打印的温度值是一样的。图3-33串口0打印的温湿度值图3-34APP的温度显示三、任务实施5.湿度上报显示在温度值上报显示的基础上,完成湿度值的上报显示。APP和网关程序都需要简单修改一下。(1)APP解析部分代码完善。case3://MQTT收到消息回传if(msg.obj.toString().contains("temperature")){StringT_val=msg.obj.toString().substring(msg.obj.toString().indexOf("temperature")+13,msg.obj.toString().indexOf("}"));Stringtext_val=T_val+"℃";binding2.text21.setText(text_val);}if(msg.obj.toString().contains("humidity")){StringH_val=msg.obj.toString().substring(msg.obj.toString().indexOf("humidity")+10,msg.obj.toString().indexOf("}"));Stringtext_val=H_val+"%";binding2.text22.setText(text_val);}//Toast.makeText(SecondActivity.this,msg.obj.toString(),Toast.LENGTH_SHORT).show();break;APP的MQTT客户端收到消息后,通过Handler回传到UI线程处理,对湿度值的解析处理和对温度值的解析处理思路是一样的,把湿度值更新到text22中即可。三、任务实施(2)网关程序部分代码完善。每2分钟上报一次消息,在上报温度消息语句后面,再调用client的publish方法发布(上报)一条湿度消息。消息的topic="/手机号/my_ESP32/post"。假如采集到的湿度值是43%,消息载荷="{"humidity":43}"。uint8_ttempTime=0;voidloop(){if(!client.connected()){reconnect();}/*两分钟上报两次温湿度信息*/if(tempTime>240){tempTime=0;DHT.read(DHT11_PIN);Serial.print("DHT.temperature=");Serial.println(DHT.temperature);Serial.print("DHT.humidity=");Serial.println(DHT.humidity);client.publish(pubTopic,("{\""+TempIdentifier+"\":"+DHT.temperature+"}").c_str());client.publish(pubTopic,("{\""+HumiIdentifier+"\":"+DHT.humidity+"}").c_str());}else{tempTime++;delay(500);}client.loop();}三、任务实施(3)结果。重新运行App和网关程序。如图3-35所示,APP显示的温度、湿度值和网关通过串口打印的值是一致的,工作正常。图3-35温湿度监测工作情况四、任务小结与练习任务小结任务6实现了温湿度的检测、数据的传输、数据解析以及数据展示,构成了一个初步的物联网系统。那么能不能进一步地通过APP远程控制硬件设备呢?留待下一个任务解决。在网关的loop函数中,有以下代码实现了MQTT断开连接时尝试重连的功能:实践练习if(!client.connected()){reconnect();}但如果WiFi断开了,貌似没有重连的机制,有什么解决办法吗?谢谢聆听2相关知识34任务小结与练习1任务实施任务引入与目标物联网APP远程控制LED一、任务引入与目标任务目标任务7将实现:APP发送MQTT消息:topic="/手机号/my_APP/set",payload="{"LedStatus":1}"或"{"LedStatus":0}"。ESP32网关收到MQTT消息后,根据解析的命令值控制所接LED的亮与灭。APP程序不需要修改,网关程序设计中需要实现MQTT消息的接收、解析及控制。任务引入任务6实现了温湿度的展示,数据流向为硬件到APP。这个数据能不能实现反方向传输呢?比如能否通过APP远程控制硬件设备呢?二、相关知识Arduino开发环境中的JavaScript对象(JSONObject)JSONObject可以包含多个成员,每个成员以name:value对(键值对,键又称为字段)呈现,如{"id":1,"temp":22}。格式要求:JSONObject用花括号表示;成员之间用逗号分隔;键(字段)和值之间用冒号分隔;键用双引号括起来,即键是一个字符串。获取JSON对象成员的值用户可以通过两种方式获取JSON对象成员的值:(1)JSON对象名.id;(2)JSON对象名["id"];其中,id是JSON对象的一个键。二、相关知识课堂讨论JSONObject可以转换为一个字符串,或者通过字符串转换得到。其中的键也是一个字符串,需要用双引号括起来。在进行程序设计时,键的双引号该如何处理,才不会造成误解呢?三、任务实施实施设备ESP32网关和DHT11温湿度传感器各一个,杜邦线若干,安装了Arduino开发环境和AndroidStudio开发环境的计算机,部署了MQTT服务器的云服务器。1.网关和LED硬件连接在任务6的基础上,连接LED灯:DHT11_DAT———ESP32_IO25DHT11_GND———ESP32_GNDDHT11_VCC———ESP32_VCC

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论