ESP32、Python、Android平台使用mqtt的基础程序,以onenet通信为例
ESP32
需要安装PubSubClient库
1 | #include <Arduino.h> |
Python
1 | import paho.mqtt.client as mqtt |
Android
- 添加权限
打开AndroidManifest.xml,加入以下两行1
2<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> - 导入第三方库
打开app下的build.gradle,添加库
1 | implementation 'org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.1.0' |
添加之后需要 *** Sync Now *** 一下
- 测试代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103package com.example.mqtt_test;
import static java.lang.Thread.sleep;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.os.Handler;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
import java.util.concurrent.ScheduledExecutorService;
public class MainActivity extends AppCompatActivity {
private String serverUri = "tcp://183.230.40.39:6002";
private String userName = ""; //产品ID
private String passWord = ""; //鉴权信息
private String clientId = ""; //设备ID
private MqttClient mqtt_client;
MqttConnectOptions options;
private ScheduledExecutorService scheduler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mqtt_init_Connect();
new Thread(new Runnable() {
@Override
public void run() {
while(true){
try {
sleep(1000);
publishMessage("light", "String message_str");
} catch (Exception e) {
}
}
}
}).start();
}
public void mqtt_init_Connect()
{
try {
//实例化mqtt_client,填入我们定义的serverUri和clientId,然后MemoryPersistence设置clientid的保存形式,默认为以内存保存
mqtt_client = new MqttClient(serverUri,clientId,new MemoryPersistence());
//创建并实例化一个MQTT的连接参数对象
options = new MqttConnectOptions();
//然后设置对应的参数
options.setUserName(userName); //设置连接的用户名
options.setPassword(passWord.toCharArray()); //设置连接的密码
options.setConnectionTimeout(30); // 设置超时时间,单位为秒
options.setKeepAliveInterval(50); //设置心跳,30s
options.setAutomaticReconnect(true); //是否重连
//设置是否清空session,设置为false表示服务器会保留客户端的连接记录,设置为true表示每次连接到服务器都以新的身份连接
options.setCleanSession(true);
//设置回调
mqtt_client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
//连接丢失后,一般在这里面进行重连
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
//publish后会执行到这里
}
@Override
public void messageArrived(String topicName, MqttMessage message) throws Exception {
//subscribe后得到的消息会执行到这里面
}
});
//连接mqtt服务器
mqtt_client.connect(options);
}catch (Exception e) {
e.printStackTrace();
}
}
public void publishMessage(String topic, String message_str){
try {
MqttMessage message = new MqttMessage();
message.setPayload(message_str.getBytes());
if(mqtt_client.isConnected()){
mqtt_client.publish(topic, message);
}
} catch (MqttException e) {
e.printStackTrace();
}
}
}
Android 数据流使用
网络配置
在res文件夹下新建xml文件夹,并在xml文件夹下新建network-security-config.xml文件,内容如下:1
2
3
4<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="true"/>
</network-security-config>添加权限
在AndroidManifest.xml添加,以使用网络功能1
2<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />继续在添加 application 添加,以使用http连接
1
android:networkSecurityConfig="@xml/network_security_config"
在app: build.gradle添加第三方库
1
2implementation 'com.google.code.gson:gson:2.8.6'
implementation 'com.squareup.okhttp3:okhttp:4.8.1'新建类Datastreams
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package com.example.http;
import java.util.List;
public class Datastreams {
private List<Datapoints> datapoints;
private String id;
public void setDatapoints(List<Datapoints> datapoints) {
this.datapoints = datapoints;
}
public List<Datapoints> getDatapoints() {
return datapoints;
}
public void setId(String id) {
this.id = id;
}
public String getId() {
return id;
}
}新建类Data
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package com.example.http;
import java.util.List;
public class Data {
private int count;
private List<Datastreams> datastreams;
public void setCount(int count) {
this.count = count;
}
public int getCount() {
return count;
}
public void setDatastreams(List<Datastreams> datastreams) {
this.datastreams = datastreams;
}
public List<Datastreams> getDatastreams() {
return datastreams;
}
}新建类Datapoints
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25package com.example.http;
public class Datapoints {
private String at;
private String value;
public void setValue(String value) {
this.value = value;
}
public String getAt() {
return at;
}
public void setAt(String at) {
this.at = at;
}
public String getValue() {
return value;
}
}新建类Datapoints
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24package com.example.http;
public class Datapoints {
private String at;
private String value;
public void setValue(String value) {
this.value = value;
}
public String getAt() {
return at;
}
public void setAt(String at) {
this.at = at;
}
public String getValue() {
return value;
}
}新建类JsonRootBean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27package com.example.http;
public class JsonRootBean {
private int errno;
private Data data;
private String error;
public void setErrno(int errno) {
this.errno = errno;
}
public int getErrno() {
return errno;
}
public void setData(Data data) {
this.data = data;
}
public Data getData() {
return data;
}
public void setError(String error) {
this.error = error;
}
public String getError() {
return error;
}
}布局文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:gravity="center_vertical"
>
<TextView
android:id="@+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:hint="温度显示区域"
android:textColor="#222222"
android:textSize="30sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:gravity="center_vertical"
>
<EditText
android:id="@+id/data2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:hint="温度修改值"
android:textColor="#222222"
android:textSize="30sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:gravity="center_vertical"
>
<TextView
android:id="@+id/data1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:hint="湿度显示区域"
android:textColor="#222222"
android:textSize="30sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:gravity="center_vertical"
>
<EditText
android:id="@+id/data3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:hint="湿度修改值"
android:textColor="#222222"
android:textSize="30sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="75dp"
android:layout_marginLeft="10dp"
android:layout_marginTop="10dp"
android:layout_marginRight="10dp"
android:gravity="center_vertical"
>
<TextView
android:id="@+id/data4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:hint="时间显示区域"
android:textColor="#222222"
android:textSize="30sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="259dp">
<Button
android:id="@+id/post"
android:layout_width="0dp"
android:layout_height="80sp"
android:layout_marginStart="40dp"
android:layout_marginTop="104dp"
android:layout_marginEnd="33dp"
android:text="修改"
android:textColor="#181616"
android:textSize="40sp"
app:layout_constraintEnd_toStartOf="@+id/get"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/get"
android:layout_width="0dp"
android:layout_height="80sp"
android:layout_marginEnd="38dp"
android:text="获取"
android:textColor="#2C2929"
android:textSize="40sp"
app:layout_constraintBaseline_toBaselineOf="@+id/post"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/post" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</LinearLayout>主程序
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171package com.example.http;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.google.gson.Gson;
import java.io.IOException;
import java.util.List;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;
public class MainActivity extends Activity implements View.OnClickListener {
private static final String DeviceID ="949106187";
private static final String ApiKey ="rJU0Stx1xI=EbsDAjwjxM0lM=II=";
private static final String key1 ="temp";
private static final String key2 ="humid";
private static final String key3 ="heart";
private static final String key4 ="h2o2";
Button GET, POST;
TextView data, data1, data2, data3, data4;
String time, value, value1, value2, value3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
GET = findViewById(R.id.get);
POST = findViewById(R.id.post);
data = findViewById(R.id.data);
data1 = findViewById(R.id.data1);
data2 = findViewById(R.id.data2);
data3 = findViewById(R.id.data3);
data4 = findViewById(R.id.data4);
GET.setOnClickListener(this);
POST.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.get:
Get();
Toast.makeText(MainActivity.this, "数据接收成功", Toast.LENGTH_SHORT).show();
break;
case R.id.post:
Post();
Toast.makeText(MainActivity.this, "数据修改成功", Toast.LENGTH_SHORT).show();
break;
}
}
public void Get() {
new Thread(new Runnable() {
@Override
public void run() {
try {
//接受温度
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder().url("http://api.heclouds.com/devices/" + DeviceID + "/datapoints?datastream_id=" + key1).header("api-key", ApiKey).build();
Response response = client.newCall(request).execute();
String responseData = response.body().string();
parseJSONWithGSON(responseData);
JsonRootBean app = new Gson().fromJson(responseData, JsonRootBean.class);
List<Datastreams> streams = app.getData().getDatastreams();
List<Datapoints> points = streams.get(0).getDatapoints();
value = points.get(0).getValue();
time = points.get(0).getAt();
data.post(new Runnable() {
@Override
public void run() {
data.setText(String.format("温度:%s°C", value));
data4.setText(String.format("时间:%s", time.substring(10, 19)));
}
});
} catch (IOException e) {
e.printStackTrace();
}
try {
//接受湿度
OkHttpClient client1 = new OkHttpClient();
Request request1 = new Request.Builder().url("http://api.heclouds.com/devices/" + DeviceID + "/datapoints?datastream_id=" + key2).header("api-key", ApiKey).build();
Response response1 = client1.newCall(request1).execute();
String responseData1 = response1.body().string();
parseJSONWithGSON(responseData1);
JsonRootBean app = new Gson().fromJson(responseData1, JsonRootBean.class);
List<Datastreams> streams = app.getData().getDatastreams();
List<Datapoints> points = streams.get(0).getDatapoints();
value1 = points.get(0).getValue();
data1.post(new Runnable() {
@Override
public void run() {
data1.setText(String.format("湿度:%s%%", value1));
}
});
} catch (IOException ex) {
ex.printStackTrace();
}
}
}).start();
}
public void Post() {
new Thread(new Runnable() {
@Override
public void run() {
try {
//更改湿度值
value2 = data2.getText().toString().trim();
OkHttpClient client = new OkHttpClient();
//数据格式从官方文档看,type用5情况
String updata = (",;" + key1 + "," + value2);
//发送type写法
RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json"), updata);
Request request = new Request.Builder().url("http://api.heclouds.com/devices/" + DeviceID + "/datapoints?type=5").post(requestBody).header("api-key", ApiKey).build();
Response response = client.newCall(request).execute();
} catch (Exception e) {
}
try {
//更改湿度值
value3 = data3.getText().toString().trim();
OkHttpClient client = new OkHttpClient();
//数据格式从官方文档看,type用5情况
String updata = (",;" + key2 + "," + value3);
//发送type写法
RequestBody requestBody = RequestBody.create(okhttp3.MediaType.parse("application/json"), updata);
Request request = new Request.Builder().url("http://api.heclouds.com/devices/" + DeviceID + "/datapoints?type=5").post(requestBody).header("api-key", ApiKey).build();
Response response = client.newCall(request).execute();
} catch (Exception e) {
}
}
}).start();
}
//解析json
private void parseJSONWithGSON(String jsonData) {
JsonRootBean app = new Gson().fromJson(jsonData, JsonRootBean.class);
List<Datastreams> streams = app.getData().getDatastreams();
List<Datapoints> points = streams.get(0).getDatapoints();
int count = app.getData().getCount();//获取数据的数量
for (int i = 0; i < points.size(); i++) {
String time = points.get(i).getAt();
String value = points.get(i).getValue();
Log.w("www","time="+time);
Log.w("www","value="+value);
}
}
}参考链接