自制APP连接OneNET---实现数据监控和下发控制(MQTT)


前言

本案例主要实现的功能是自制手机APP连接OneNET的MQTT服务器,同时接收和显示单片机的数据,对单片机上LED灯进行远程控制。
虽说OneNET上有应用管理,可以实现手机端控制单片机,但是这样做有点简单,达不到毕设水平,课设勉强可以及格。如果是自己做一款APP来控制单片机,顿时高大上很多。


一、前期准备

1、STM32F103C8T6最小系统板
2、ESP8266-01S模块
3、在OneNET平台上创建MQTT协议的产品和创建两个设备
4、安装E4A软件,软件不大几百兆下载链接

二、功能介绍

1、自制APP页面展示

由于是连接OneNET的MQTT服务器,故地址端口是固定不变的。
产品ID、设备ID、鉴权信息可以在OneNET平台上获取,这个不必多说。
订阅按钮:订阅主题为EndTopic的主题
发布按钮:发布主题为AppToic的消息,消息内容是123456
三个绿色框分别是光照值、温度值、湿度值。这里的温湿度做了自增处理,不是实际温湿度。
第一个开关:发布主题为AppToic的消息,消息内容是KEY:1或KEY:0
第二个开关:发布主题为AppToic的消息,消息内容是LED1:1或LED1:0

2、串口助手界面

1、EndTopic是单片机端发布消息的主题
2、{“Light”:152.7,“Temp”:104,“Humi”:104}是消息的内容
3、AppTopic是来自APP端发布的消息主题
4、KEY:1是消息内容
在这里插入图片描述

3、OneNET平台显示

APP端和单片机端的设备都显示在线。
在这里插入图片描述

三、单片机端功能实现

1、修改OneNET官方提供的例程

(1)将芯片型号由原先的STM32F103RC更改为STM32F103C8
(2)在全局宏定义中将STM32F10X_HD更改为STM32F10X_MD
(3)将原先的startup_stm32f10x_hd.s的启动文件移除,添加startup_stm32f10x_md.s的
启动文件
(4)在stm32f10x.h文件中,将HSE_VALUE宏的值由原先的12M改为8M
(5)在onenet.c文件上方的三个宏定义分别填入连接平台的三要素
(6)在esp8266.c中,定义了系统需要连接热点名称和密码
(7)从其他例程中移植OneNet_SendData();函数
(8)移植传感器采集数据和LED(PC13)的初始化代码
在这里插入图片描述

2、主函数代码

int main(void)
{
	unsigned short timeCount = 0;	//发送间隔变量
	
	unsigned char *dataPtr = NULL;
	
	Hardware_Init();				//初始化外围硬件
	
	ESP8266_Init();					//初始化ESP8266
	
	while(OneNet_DevLink())			//接入OneNET
		DelayXms(500);
	
	Beep_Set(BEEP_ON);				//鸣叫提示接入成功
	DelayXms(250);
	Beep_Set(BEEP_OFF);
	
	OneNet_Subscribe(SubTopics, 1);
	
	while(1)
	{
		if(++timeCount >= 300)									//发送间隔3s
		{
			//UsartPrintf(USART_DEBUG, "OneNet_Publish\r\n");
			light = LIght_Intensity();  //读取光照强度的值
			//可以在这读取温湿度值
			
			OneNet_SendData();//发送数据到手机APP
			
			timeCount = 0;
			ESP8266_Clear();
		}
		
		dataPtr = ESP8266_GetIPD(0);   
		if(dataPtr != NULL)
			OneNet_RevPro(dataPtr);    //下发命令处理
		
		DelayXms(10);
	}
}

3、上传数据到APP

上传数据相关代码如下:

void OneNet_SendData(void)
{
	char buf[256];
	
	memset(buf, 0, sizeof(buf));
	
	OneNet_FillBuf(buf);									//封装数据流
	
	//ESP8266_SendData((unsigned char *)buf, strlen(buf));	//上传数据
	OneNet_Publish(PubTopics, buf);   //发布消息	
}

数据封装函数
这个函数的功能是将需要上传的数据打包成JSON格式。

extern u8 temp,humi;
extern	float light;
extern const char PubTopics[] ;    //发布主题
unsigned char OneNet_FillBuf(char *buf)
{
	
	char text[16];
	
	memset(text, 0, sizeof(text));
	
	strcpy(buf, "{");
	
	memset(text, 0, sizeof(text));
	sprintf(text, "\"Light\":%.1f,",light);
	strcat(buf, text);
	
	memset(text, 0, sizeof(text));
	sprintf(text, "\"Temp\":%d,", temp++);
	strcat(buf, text);
	
	memset(text, 0, sizeof(text));
	sprintf(text, "\"Humi\":%d", humi++);
	strcat(buf, text);
	
	strcat(buf, "}");
	
	return strlen(buf);
}

4、命令处理

当接收到来自APP端下发的命令后,会调用下发命令处理函数OneNet_RevPro(),在该函数内根据消息内容对单片机进行控制。
函数内部的部分代码如下:

	dataPtr = strchr(req_payload, ':');					//搜索':'

	if(dataPtr != NULL && result != -1)					//如果找到了
	{
		dataPtr++;
		
		while(*dataPtr >= '0' && *dataPtr <= '9')		//判断是否是下发的命令控制数据
		{
			numBuf[num++] = *dataPtr++;
		}
		
		num = atoi((const char *)numBuf);			//转为数值形式
		
		if(strstr((char *)req_payload, "LED1"))		//搜索"LED1"
		{
			UsartPrintf(USART_DEBUG,"LED1 = %d\r\n", num);     //num就是LED1:V 中V的值
			LED1 = !num;                   			 //控制LED灯,低电平点亮
		}
		else if(strstr((char *)req_payload, "KEY"))	//搜索"KEY"
		{
			UsartPrintf(USART_DEBUG,"KEY = %d\r\n", num);
		}
		//继续else if添加其他命令
		
	}

四、APP端功能实现

这部分主要讲如何制作手机APP连接OneNET平台,并且获取数据和下发命令控制LED灯。APP是使用E4A中文安卓编程开发的,编程思维和C语言很相似,并且是中文编程,只需一天就能基本掌握。

1、连接MQTT服务器

接入云平台主要依靠的是E4A上面的mqtt通讯组件,这个组件命令有八个方法,七个事件。从单片机编程的角度来看,方法相当于函数,可以人为的去调用,事件相当于中断,不需人为调用。而连接OneNET的MQTT服务器就使用了连接服务器方法。
连接服务器方法的调用需要传入七个参数,参数一是服务器地址端口,即OneNET的MQTT服务器地址和端口;参数二填入产品ID;参数三填入鉴权信息;参数四填入设备ID;通过点击连接按钮,就可以调用连接服务器方法,实现接入云平台的功能。

事件 连接按钮.被单击()
	
	如果 连接按钮.标题 = "连接" 则   ' 产品ID框.内容为空会闪退
		连接按钮.标题 = "断开"
	    mqtt通讯1.连接服务器(地址端口框.内容,产品ID框.内容,鉴权信息框.内容,设备ID框.内容,,,5)

	否则 
		连接按钮.标题 = "连接"
	    mqtt通讯1.断开连接()
	结束 如果

结束 事件

2、实现订阅与发布

订阅和发布分别使用mqtt通讯组件中的订阅消息和发布消息的方法,通过对应的按钮单击事件分别调用这两个方法。
订阅与发布程序编写如下所示。

事件 订阅按钮.被单击()
	
	mqtt通讯1.订阅消息(订阅主题框.内容,0)
	
结束 事件

事件 发布按钮.被单击()
	mqtt通讯1.发送消息(发布主题框.内容,文本到字节(发布消息框.内容,"UTF-8"),1,)
结束 事件

订阅消息方法的调用要传入两个参数,参数一是订阅的主题,为了接收单片机端发布的主题消息,这里订阅的是“EndTopic”;参数二是消息策略,可以填入0、1、2,这里填入0,表示只会发送一次推送消息,收不收都不关心,这是因为单片机端会多次发布主题消息,故不需要每次都要接收到。
发布消息方法的调用要传入四个参数,参数一是消息主题,这里填“AppTopic”;参数二是消息内容,参数三是消息策略,这里填入1

3、APP显示数据

由于单片机端发布的消息不只有光照值,还有温湿度等内容,为了方便解读出数据,在单片机端将这些数据打包为JSON格式,然后再发布出去。
当APP端收到消息后,就会触发mqtt通讯里面的收到消息事件,在这事件里面,我们利用E4A中的JSON操作组件对消息内容进行解析,将解析处理的内容存放在JSON对象里面,然后使用JSON操作组件里面的取文本值方法获取JSON对象里指定数据成员的值,最后将这个值赋值给对应的显示标签。
收到消息事件程序编写如下所示

事件 mqtt通讯1.收到消息(消息主题 为 文本型, 消息内容 为 字节型(), 消息策略 为 整数型)
	
	接收框.内容 = 接收框.内容 & "\n" & "主题:" & 消息主题 & "\n内容:" & 字节到文本(消息内容,"UTF-8") & "\n策略:" & 消息策略
	接收框.置光标位置(取文本长度(接收框.内容))
	
	'开始json解析
	变量 JSON对象 为 对象
	JSON对象 = JSON操作1.解析(字节到文本(消息内容,"UTF-8"))
	调试输出("JSON成员数:" & JSON操作1.取成员数(JSON对象))
	光照值标签.标题 = "Light:" & JSON操作1.取文本值(JSON对象 , "Light")
	温度值标签.标题 = "Temp:" & JSON操作1.取文本值(JSON对象 , "Temp")
	湿度值标签.标题 = "Humi:" & JSON操作1.取文本值(JSON对象 , "Humi")
	
结束 事件

4、APP下发命令

这里以灯光开关的控制为例子,其他控制功能类似。灯光开关组件状态被改变事件程序如下所示。

事件 开灯按钮.被单击()
	
	如果 连接按钮.标题 = "连接" 则 '未连接时退出事件
		退出
	结束 如果
		
	如果 开灯按钮.标题 = "开灯" 则
    开灯按钮.标题 = "关灯"
    mqtt通讯1.发送消息(发布主题框.内容,文本到字节("LED1:1","UTF-8"),1,)
	
	否则  
	开灯按钮.标题 = "开灯"	
	mqtt通讯1.发送消息(发布主题框.内容,文本到字节("LED1:0","UTF-8"),1,)
	结束 如果
		
结束 事件

单片机端接收到由APP端发布出来的消息后,会通过消息解包函数取出数据包的主题、消息内容、消息策略,如果消息策略是1就先回复Ack给服务器,然后再判断消息内容里面有没有程序设计好的命令字符串,如果有就执行相应的程序。


总结

有需要的话,可以问我拿源码,我有空就会回复。
代码下载链接放这里了:https://github.com/J-CHUN/OneNET-MQTT-APP.git

### 回答1: 要在Android上创建连接OneNet的应用程序,您需要使用OneNet提供的APISDK。您可以使用HTTP API或MQTT协议来连接OneNet。以下是一些步骤: 1.注册OneNet账户并创建设备数据流。 2.下载OneNet提供的Android SDK并将其添加到您的项目中。 3.使用SDK中提供的API连接OneNet并发送数据4.在应用程序中添加UI元素以显示从OneNet接收的数据。 5.测试应用程序并确保它可以正确连接发送数据OneNet。 请注意,您需要了解Android开发网络编程的基础知识才能成功创建连接OneNet的应用程序。 ### 回答2: 要在Android上创建一个连接OneNet的应用程序,您需要首先了解OneNet的API接口Android的编程语言Java。 步骤如下: 1.注册一个OneNet账户,获取API的Key。 2.创建一个Android项目并在build.gradle文件中添加以下依赖项: ``` compile 'com.squareup.okhttp3:okhttp:3.10.0' compile 'com.google.code.gson:gson:2.8.2' ``` 这里我们使用了OKHttpClientGson库。 3.创建一个HttpGet请求并从OneNet获取数据,然后将数据显示在Android应用程序中。示例代码如下: ``` String apiKey = "你的APIKEY"; String deviceId = "你的设备ID"; String url = "http://api.heclouds.com/devices/" + deviceId + "/datapoints"; OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(url) .addHeader("api-key", apiKey) .build(); Response response = client.newCall(request).execute(); String responseData = response.body().string(); Gson gson = new Gson(); JsonObject jsonObject = gson.fromJson(responseData, JsonObject.class); JsonArray jsonArray = jsonObject.getAsJsonArray("datastreams"); JsonObject dataStreamObject = jsonArray.get(0).getAsJsonObject(); JsonArray dataPointsArray = dataStreamObject.getAsJsonArray("datapoints"); JSONObject latestDataObject = dataPointsArray.get(dataPointsArray.size()-1).getAsJsonObject(); String latestValue = latestDataObject.get("value").getAsString(); ``` 4.创建一个HttpPost请求并将数据发送到OneNet。示例代码如下: ``` String apiKey = "你的APIKEY"; String deviceId = "你的设备ID"; String url = "http://api.heclouds.com/devices/" + deviceId + "/datapoints"; OkHttpClient client = new OkHttpClient(); MediaType JSON = MediaType.parse("application/json; charset=utf-8"); JSONObject jsonObject = new JSONObject(); try { jsonObject.put("temperature", "25"); jsonObject.put("humidity", "70"); } catch (JSONException e) { e.printStackTrace(); } RequestBody requestBody = RequestBody.create(JSON, jsonObject.toString()); Request request = new Request.Builder() .url(url) .addHeader("api-key", apiKey) .post(requestBody) .build(); Response response = client.newCall(request).execute(); ``` 这是一个简单的例子,您可以根据您的需要实际情况来修改代码。 5.在Android应用程序中操作OneNet数据时,务必考虑到数据的安全性,避免出现数据泄露非法访问的情况。 总之,连接OneNet涉及到HTTP请求、数据的解析安全保护等方面的知识,您需要具备一定的编程基础专业知识才能够实现。希望这篇答案对您有所帮助。 ### 回答3: Android创建app连接OneNet,需要按以下步骤进行: 1.注册OneNet平台账户,获取Device IDAPI Key。 2.在Android Studio中新建项目,并导入MQTT库。 3.创建MQTT连接的方法,包括设置连接参数,订阅主题等。 4.使用OkHttp框架发送HTTP请求,实现OneNet平台的交互。 5.编写App界面,包括数据显示、控制按钮等。 具体步骤如下: 1.注册OneNet平台账户,登录后进入“设备管理”页面,新建一个“设备”,获取Device IDAPI Key。 2.在Android Studio中新建项目,依次点击File - New - Project,选择“Empty Activity”模板,设置项目名称包名。点击“Finish”按钮,完成新建项目。 3.执行以下操作: (1)导入MQTT库:在app的build.gradle文件中添加以下依赖: ``` implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5' ``` (2)创建MQTT连接的方法: ``` private void connectMqtt() { try { String serverURI = "tcp://mqtt.heclouds.com:1883"; String clientId = "paho-android-example" + System.currentTimeMillis(); MqttConnectOptions options = new MqttConnectOptions(); options.setCleanSession(true); options.setUserName(mDeviceId); options.setPassword(mApiKey.toCharArray()); IMqttClient client = new MqttClient(serverURI, clientId); client.setCallback(new MqttCallbackExtended() { @Override public void connectComplete(boolean reconnect, String serverURI) { String topic = "/mqtt"; int qos = 1; try { IMqttToken subToken = client.subscribeWithResponse(topic, qos); } catch (MqttException e) { e.printStackTrace(); } } @Override public void connectionLost(Throwable cause) { } @Override public void messageArrived(String topic, MqttMessage message) throws Exception { String msg = new String(message.getPayload()); // 处理收到的消息 } @Override public void deliveryComplete(IMqttDeliveryToken token) { } }); client.connect(options); } catch (MqttException e) { e.printStackTrace(); } } ``` 其中mDeviceIdmApiKey分别为OneNet平台设备的IDAPI Key。 4.使用OkHttp框架发送HTTP请求,实现OneNet平台的交互。例如,查询某个数据流的最新数值: ``` private void getLatestData() { OkHttpClient client = new OkHttpClient(); String url = "http://api.heclouds.com/devices/" + mDeviceId + "/datastreams/" + mDataStreamId; Request request = new Request.Builder() .addHeader("api-key", mApiKey) .url(url) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { String body = response.body().string(); // 解析JSON数据,获取最新数值 } }); } ``` 其中mDataStreamId为OneNet平台的数据流ID。 5.在App界面中,显示数据控制开关等。例如,显示最新数值: ``` private void showLatestData(String value) { runOnUiThread(() -> { mValueTextView.setText("最新数值:" + value); }); } ``` 例如,控制开关: ``` private void toggleSwitch(boolean on) { OkHttpClient client = new OkHttpClient(); String url = "http://api.heclouds.com/cmds?device_id=" + mDeviceId; String body = "[{\"sn\":\"" + System.currentTimeMillis() + "\",\"datastreams\":[{\"id\":\"" + mDataStreamId + "\",\"datapoints\":[{\"value\":\"" + (on ? "1" : "0") + "\"}]}]}]"; Request request = new Request.Builder() .addHeader("api-key", mApiKey) .url(url) .post(RequestBody.create(MediaType.parse("application/json"), body)) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { String body = response.body().string(); Log.d("TAG", "toggleSwitch: " + body); // 解析JSON数据,检查控制指令是否成功发送到OneNet平台 } }); } ``` 除了以上基本步骤,根据具体需求,可添加定时上传数据、推送提醒等功能。例如,定时上传数据: ``` private void uploadData(int value) { OkHttpClient client = new OkHttpClient(); String url = "http://api.heclouds.com/devices/" + mDeviceId + "/datastreams/" + mDataStreamId + "/datapoints"; String body = "{\"datastreams\":[{\"id\":\"" + mDataStreamId + "\",\"datapoints\":[{\"value\":\"" + value + "\"}]}]}"; Request request = new Request.Builder() .addHeader("api-key", mApiKey) .url(url) .post(RequestBody.create(MediaType.parse("application/json"), body)) .build(); client.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { e.printStackTrace(); } @Override public void onResponse(Call call, Response response) throws IOException { String body = response.body().string(); Log.d("TAG", "uploadData: " + body); } }); } ``` 调用该方法,可定时上传数值到OneNet平台。例如,每隔1分钟执行一次上传: ``` Observable.interval(1, TimeUnit.MINUTES) .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(count -> { Random random = new Random(); int value = random.nextInt(100); uploadData(value); }); ```
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

⁽⁽ଘ晴空万里ଓ⁾⁾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值