實作原理:
這裡設計的是一個監測控制智能風扇的APP,可以實時監測目前溫度、濕度及下位機的傳感器、控制器件的一些狀态。
一、設計流程:
- Android app項目建立;
- UI控制界面設計;
- 導入MQTT jar包;
- 配置聯網權限;
- 配置MQTT伺服器連接配接參數;
- MQTT.fx實作聯調;
二、設計實作
1、Android app項目建立
項目建立這裡就不過多贅述了!
2、UI控制界面設計
模拟器界面
手機app界面
這個顯示界面代碼相對簡單,有需要的可以參考一下,代碼如下:
<?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:orientation="vertical"
android:background="#078307"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="78dp">
<TextView
android:layout_width="match_parent"
android:layout_marginTop="10dp"
android:text="智能溫控風扇系統設計"
android:textSize="24sp"
android:layout_marginLeft="6dp"
android:layout_gravity="center"
android:textColor="@color/white"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:background="#FAF6F6"
android:orientation="vertical"
android:layout_height="710dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_marginTop="20dp"
android:layout_height="wrap_content">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="200dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
app:cardCornerRadius="20dp">
<ImageView
android:id="@+id/m_im_1"
android:layout_width="wrap_content"
android:src="@drawable/img_3"
android:layout_height="wrap_content"/>
</androidx.cardview.widget.CardView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_marginTop="30dp"
android:orientation="vertical"
android:layout_height="300dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_marginTop="30sp"
android:orientation="horizontal"
android:layout_height="wrap_content">
<TextView
android:id="@+id/m_temp"
android:layout_width="wrap_content"
android:text="溫度:0 ℃"
android:textSize="16sp"
android:layout_weight="1"
android:textColor="@color/black"
android:layout_marginLeft="30dp"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/m_humi"
android:layout_weight="1"
android:layout_width="wrap_content"
android:text="濕度:0 %"
android:textSize="16sp"
android:textColor="@color/black"
android:layout_marginLeft="30dp"
android:layout_height="wrap_content"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_marginTop="50dp"
android:padding="30dp"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:text="MQTT連接配接狀态:"
android:textColor="@color/black"
android:textSize="16sp"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/m_mqtt"
android:layout_width="wrap_content"
android:text=" "
android:textColor="@color/black"
android:textSize="16sp"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageButton
android:layout_width="30dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:layout_height="40dp"/>
<ImageButton
android:layout_width="30dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:layout_height="40dp"/>
<ImageButton
android:layout_width="30dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:layout_height="40dp"/>
<ImageButton
android:layout_width="30dp"
android:layout_marginRight="10dp"
android:layout_weight="1"
android:layout_height="40dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:orientation="horizontal"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:text="我的"
android:gravity="center"
android:textSize="16sp"
android:layout_weight="1"
android:layout_marginLeft="10dp"
android:textColor="@color/white"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:text="我的"
android:gravity="center"
android:textSize="16sp"
android:layout_weight="1"
android:layout_marginLeft="10dp"
android:textColor="@color/white"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:text="我的"
android:gravity="center"
android:textSize="16sp"
android:layout_weight="1"
android:layout_marginLeft="10dp"
android:textColor="@color/white"
android:layout_height="wrap_content"/>
<TextView
android:layout_width="wrap_content"
android:text="我的"
android:gravity="center"
android:textSize="16sp"
android:layout_weight="1"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:textColor="@color/white"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
3、導入MQTTjar包
進入正題,開始導入MQTT所需要的jar包:
jar包連結 連結:https://pan.baidu.com/s/1hLt1xiL67dhbJ3v3MKfUlw
提取碼:wmmh
下載下傳jar包後直接複制這個jar包
然後給粘貼至libs目錄下
點選OK即可
導入
然後滑鼠右鍵給它添加依賴
點選OK
等待建構完成即可.
此時我們來到java代碼界面敲MQTT就可以看到很多方法
好,到了這一步就可以添加MQTT的配置代碼了
在onCreate後面添加下列代碼
添加代碼
// MQTT初始化
private void Mqtt_init()
{
try {
//host為主機名,test為clientid即連接配接MQTT的用戶端ID,一般以用戶端唯一辨別符表示,MemoryPersistence設定clientid的儲存形式,預設為以記憶體儲存
client = new MqttClient(host, mqtt_id,
new MemoryPersistence());
//MQTT的連接配接設定
MqttConnectOptions options = new MqttConnectOptions();
//設定是否清空session,這裡如果設定為false表示伺服器會保留用戶端的連接配接記錄,這裡設定為true表示每次連接配接到伺服器都以新的身份連接配接
options.setCleanSession(false);
//設定連接配接的使用者名
options.setUserName(userName);
//設定連接配接的密碼
options.setPassword(passWord.toCharArray());
// 設定逾時時間 機關為秒
options.setConnectionTimeout(10);
// 設定會話心跳時間 機關為秒 伺服器會每隔1.5*20秒的時間向用戶端發送個消息判斷用戶端是否線上,但這個方法并沒有重連的機制
options.setKeepAliveInterval(20);
//設定回調
client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
//連接配接丢失後,一般在這裡面進行重連
System.out.println("connectionLost----------");
//startReconnect();
}
@Override
public void deliveryComplete(IMqttDeliveryToken token) {
//publish後會執行到這裡
System.out.println("deliveryComplete---------"
+ token.isComplete());
}
@Override
public void messageArrived(String topicName, MqttMessage message)
throws Exception {
//subscribe後得到的消息會執行到這裡面
System.out.println("messageArrived----------");
Message msg = new Message();
msg.what = 3; //收到消息标志位
// msg.obj = topicName + "---" +message.toString();
msg.obj = message.toString();
handler.sendMessage(msg); // hander 回傳
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
// MQTT連接配接函數
private void Mqtt_connect() {
new Thread(new Runnable() {
@Override
public void run() {
try {
if(!(client.isConnected()) ) //如果還未連接配接
{
MqttConnectOptions options = null;
client.connect(options);
Message msg = new Message();
msg.what = 31;
handler.sendMessage(msg);
}
} catch (Exception e) {
e.printStackTrace();
Message msg = new Message();
msg.what = 30;
handler.sendMessage(msg);
}
}
}).start();
}
// MQTT重新連接配接函數
private void startReconnect() {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
if (!client.isConnected()) {
Mqtt_connect();
}
}
}, 0*1000, 10 * 1000, TimeUnit.MILLISECONDS);
}
// 訂閱函數 (下發任務/指令)
private void publishmessageplus(String topic,String message2)
{
if (client == null || !client.isConnected()) {
return;
}
MqttMessage message = new MqttMessage();
message.setPayload(message2.getBytes());
try {
client.publish(topic,message);
} catch (MqttException e) {
e.printStackTrace();
}
}
/* ========================================================================================== */
不出意外,這裡會出現一堆報紅
不用慌,這是因為有一些方法還沒建構,有一些參數還沒聲明,我們一步一步來;
光标放置後按alt+Enter後,有部分參數就會自動建構,開幹
然後把下列處理代碼添加至主函數(這個位置)
Mqtt_init();
startReconnect();
handler = new Handler(Looper.myLooper()) {
@SuppressLint("SetTextI18n")
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what){
case 1: //開機校驗更新回傳
break;
case 2: // 回報回傳
break;
case 3: //MQTT 收到消息回傳 UTF8Buffer msg=new UTF8Buffer(object.toString());
System.out.println(msg.obj.toString()); // 顯示MQTT資料
break;
case 30: //連接配接失敗
Toast.makeText(MainActivity.this,"連接配接失敗" ,Toast.LENGTH_SHORT).show();
break;
case 31: //連接配接成功
Toast.makeText(MainActivity.this,"連接配接成功" ,Toast.LENGTH_SHORT).show();
try {
client.subscribe(mqtt_sub_topic,1);
} catch (MqttException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
};
/* -------------------------------------------------------------------------------------- */
好,把這個配置代碼加上去
private ScheduledExecutorService scheduler;
private MqttClient client;
private Handler handler;
private String host = "tcp://114.132.53.92:1883"; // TCP協定
private String userName = "aixin123456";
private String passWord = "aixin123456";
private String mqtt_id = "1353023461";
private String mqtt_sub_topic = "mqtt135";
private String mqtt_pub_topic = "esp135";
那麼到達這一步就不會有報錯了! 解決
4、配置聯網權限
在事件清單中添加聯網權限
<!--允許程式打開網絡套接字-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允許程式擷取網絡狀态-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
5、配置伺服器參數
這裡的伺服器連接配接的參數注意一定要修改,這裡連接配接伺服器位址可以填寫我的伺服器位址(“tcp://114.132.53.92:1883”),當然也可以使用官方公用的MQTT伺服器位址或者用别人的都是可以的;然後就是使用者名和密碼,一定不要用這裡我填寫的這個,可以用自己的QQ加上一些英文,或者自定義一些内容都是可以的,注意不要用我這裡填寫的這個!!! 然後就是訂閱和釋出号可以随意起,建議不用下面這些!
private String host = "tcp://124.132.53.92:1883"; // TCP協定
private String userName = "aixiA123456";
private String passWord = "aixiA123456";
private String mqtt_id = "1653223461";
private String mqtt_sub_topic = "mqtt135";
private String mqtt_pub_topic = "esp135";
好!配置完以上步驟之後,咱們就可以下載下傳到模拟機或者真機測試一下了,這裡我用的真機測試,不用慌!直接下載下傳運作,彈窗彈出連接配接成功!完美
真機運作畫面
那麼到這裡我們的app已經成功連接配接了MQTT伺服器了!
6、MQTT.fx實作聯調
這裡需要使用到一個測試軟體 MQTT.fx
這裡不提供軟體安裝包(我的找不到按轉包在哪了),網上有教程,也可以去官網下載下傳
這裡的連接配接伺服器位址填114.132.53.92或者是你自己app中連接配接的位址,端口1883,clientld_ID可以自己填
使用者名和密碼也可以自己填寫(需要注意的是,這裡填寫的這些其實是模拟你下位機的連接配接使用者資訊,也就是你STM32通過ESP8266連接配接MQTT伺服器的資訊)
點選這裡,填寫釋出号以及填寫要發往app中的資訊,點選Publish
然後就可以看的到Android Studio調試台下的接收到了資料,到了這裡是不是就實作了下位機上傳資料至MQTT伺服器至用戶端手機APP
這裡再介紹一種簡單的Json格式資料處理吧!
簡單的Json資料格式模拟下位機資料
{"name":"ESP135","Temp":"26","Humi":"78"}
這裡我們就要在app中添加一個Json資料處理的函數,形參就是需要處理的字元串
// Json資料解析
private void parseJsonobj(String jsonobj){
// 解析json
try {
JSONObject jsonObject = new JSONObject(jsonobj);
String name = jsonObject.getString("name");
String temp = jsonObject.getString("Temp");
String humi = jsonObject.getString("Humi");
m_temp.setText("溫度: "+temp+" ℃ ");
m_humi.setText("濕度: "+humi+" % ");
} catch (JSONException e) {
e.printStackTrace();
}
}
app中接收到的資料
經過處理後就可以在我們app的控件中以指定格式顯示
這樣是不是感覺就出來了!好到此那麼我們上位機資料接收就差不多了
嗯,那麼app向下位機發送資料呢!其實也就是訂閱号與STM32+ESP的資訊關聯後,經過一個函數就可以下發資料了,下一篇下位機(STM32+ESP)再詳細介紹吧!發送的函數已經添加在上述的代碼中了;這裡貼出來一個示例代碼,簡單介紹一下,一個按鍵然後下發資料 publishmessageplus(mqtt_pub_topic,"{\"set_curtain\": \"fB}");
// 關閉控件點選事件
private void button_guan(View v){
if(curtain_flag == 0){
curtain_flag = 1;
// 發送指令讓下位機關閉窗簾
publishmessageplus(mqtt_pub_topic,"{\"set_curtain\": \"fB}");
}
mtv_1.setText("關閉");
}
最後,嗯就這樣!第一次寫這麼長篇的學習記錄,也是對自己所學内容的一種鞏固,希望能幫到有需要的同志,如果有錯誤的地方還請多多見諒!謝謝!!!