天天看點

監測控制智能風扇的安卓MQTT app

作者:沃愛單片機

實作原理:

這裡設計的是一個監測控制智能風扇的APP,可以實時監測目前溫度、濕度及下位機的傳感器、控制器件的一些狀态。

一、設計流程:

  1. Android app項目建立;
  2. UI控制界面設計;
  3. 導入MQTT jar包;
  4. 配置聯網權限;
  5. 配置MQTT伺服器連接配接參數;
  6. MQTT.fx實作聯調;

二、設計實作

1、Android app項目建立

項目建立這裡就不過多贅述了!

監測控制智能風扇的安卓MQTT app

2、UI控制界面設計

模拟器界面

監測控制智能風扇的安卓MQTT app

手機app界面

監測控制智能風扇的安卓MQTT 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包

監測控制智能風扇的安卓MQTT app

然後給粘貼至libs目錄下

監測控制智能風扇的安卓MQTT app

點選OK即可

監測控制智能風扇的安卓MQTT app

導入

監測控制智能風扇的安卓MQTT app

然後滑鼠右鍵給它添加依賴

監測控制智能風扇的安卓MQTT app

點選OK

監測控制智能風扇的安卓MQTT app

等待建構完成即可.

此時我們來到java代碼界面敲MQTT就可以看到很多方法

監測控制智能風扇的安卓MQTT app

好,到了這一步就可以添加MQTT的配置代碼了

在onCreate後面添加下列代碼

監測控制智能風扇的安卓MQTT app

添加代碼

// 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();
        }
    }
    /* ========================================================================================== */           

不出意外,這裡會出現一堆報紅

監測控制智能風扇的安卓MQTT app

不用慌,這是因為有一些方法還沒建構,有一些參數還沒聲明,我們一步一步來;

光标放置後按alt+Enter後,有部分參數就會自動建構,開幹

監測控制智能風扇的安卓MQTT app

然後把下列處理代碼添加至主函數(這個位置)

監測控制智能風扇的安卓MQTT app
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";           
監測控制智能風扇的安卓MQTT app

那麼到達這一步就不會有報錯了! 解決

4、配置聯網權限

在事件清單中添加聯網權限

監測控制智能風扇的安卓MQTT app
<!--允許程式打開網絡套接字-->
    <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";           

好!配置完以上步驟之後,咱們就可以下載下傳到模拟機或者真機測試一下了,這裡我用的真機測試,不用慌!直接下載下傳運作,彈窗彈出連接配接成功!完美

真機運作畫面

監測控制智能風扇的安卓MQTT app

那麼到這裡我們的app已經成功連接配接了MQTT伺服器了!

6、MQTT.fx實作聯調

這裡需要使用到一個測試軟體 MQTT.fx

這裡不提供軟體安裝包(我的找不到按轉包在哪了),網上有教程,也可以去官網下載下傳

這裡的連接配接伺服器位址填114.132.53.92或者是你自己app中連接配接的位址,端口1883,clientld_ID可以自己填

監測控制智能風扇的安卓MQTT app

使用者名和密碼也可以自己填寫(需要注意的是,這裡填寫的這些其實是模拟你下位機的連接配接使用者資訊,也就是你STM32通過ESP8266連接配接MQTT伺服器的資訊)

監測控制智能風扇的安卓MQTT app

點選這裡,填寫釋出号以及填寫要發往app中的資訊,點選Publish

監測控制智能風扇的安卓MQTT app

然後就可以看的到Android Studio調試台下的接收到了資料,到了這裡是不是就實作了下位機上傳資料至MQTT伺服器至用戶端手機APP

這裡再介紹一種簡單的Json格式資料處理吧!

監測控制智能風扇的安卓MQTT app

簡單的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中接收到的資料

監測控制智能風扇的安卓MQTT app

經過處理後就可以在我們app的控件中以指定格式顯示

監測控制智能風扇的安卓MQTT 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("關閉");
    }           

最後,嗯就這樣!第一次寫這麼長篇的學習記錄,也是對自己所學内容的一種鞏固,希望能幫到有需要的同志,如果有錯誤的地方還請多多見諒!謝謝!!!