目錄
一、前言
二、實驗工具
1.野火F103開發(fā)板
?2.MQTT代理工具mqtt.fx
?三、安卓APP代碼?
1.建立工程
2.導入Java jar包
3.布局文件activity_main
4.Mainactivity
5、配置聯(lián)網權限
6.測試APP
?7.導出apk安裝包
?四、STM32實驗板代碼
1.main函數(shù)
2.esp8266
?3.onenet
?4.小總結
五、測試
1.測試app與mqtt的連接狀態(tài)
2.將app與實驗板同時連接mqtt服務器,實現(xiàn)遠程控制
?六、總結
一、前言
這其實就是一個簡單的物聯(lián)網小型實驗,重要的是要理解其基本原理,如果不理解的話不清楚要從哪里下手。這個實驗就是讓APP和STM32實驗板都連接網絡的前提下,同時能連接到mqtt服務器,實現(xiàn)app遠程控制實驗板的狀態(tài)。該實驗可以實現(xiàn)以下內容:
- 實現(xiàn)STM32控制LED燈顯示7種顏色顯示。
- 實現(xiàn)STM32控制蜂鳴器響和停。
- 實現(xiàn)STM32通過NTC傳感器測量溫度。
- 實現(xiàn)STM32通過串口調試助手顯示溫度。
- 實現(xiàn)STM32控制ESP8266連接WIFI路由器
- 實現(xiàn)STM32成功連接MQTT服務器
- 實現(xiàn)STM32成功發(fā)布MQTT溫度主題
- 實現(xiàn)STM32成功訂閱MQTT控制量主題
- 實現(xiàn)手機APP顯示溫度。
- 實現(xiàn)手機APP控制LED燈顯示不同顏色
首先就是要開發(fā)一個app,可以用很多語言寫APP,我這里用的是Android語言(基礎知識不牢的用Android studio寫比較難,安卓代碼簡直就是又臭又長,學過前端的可以用HBuilder寫),app里面添加相關的控件以及點擊事件 。?
再者就是用keil5寫實驗板的代碼,單片機知識不硬的建議直接按照我下面提到的方法更改相關內容就可以了,因為實在太難啦!
二、實驗工具
這里指的是我用到的實驗用具,也可以靈活多變,不一定要跟我的一模一樣。
1.野火F103開發(fā)板
這個板簡直就是太適合嵌入式開發(fā)初學者
?2.MQTT可視化工具mqtt.fx
?三、安卓APP代碼?
1.建立工程
點擊左上角File,然后new Project建立新工程
?語言選擇Java,不要選錯了。
2.導入Java jar包
鏈接:百度網盤 請輸入提取碼
?方法自己去百度一下,網上的教程很詳細。
3.布局文件activity_main
<?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"
android:background="@drawable/cxk"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="10dp">
<TextView
android:id="@+id/m_temp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="當前溫度:"
android:textColor="@color/black"
android:textSize="20sp"
android:layout_marginLeft="25dp"/>
<TextView
android:id="@+id/temp_tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textSize="20sp"
android:textColor="@color/black"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_marginTop="10dp"
android:layout_marginLeft="25dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="MQTT連接狀態(tài):"
android:textColor="@color/black"
android:textSize="20sp" />
<TextView
android:id="@+id/m_mqtt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@color/black"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:layout_marginTop="10dp"
android:layout_marginLeft="25dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="實驗板狀態(tài):"
android:textColor="@color/black"
android:textSize="20sp" />
<TextView
android:id="@+id/Light_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="@color/橙紅色"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="460dp"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="392dp"
android:layout_marginTop="60dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="30dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="燈按鈕"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="5dp">
<Button
android:id="@+id/off"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="關燈" />
<Button
android:id="@+id/red"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="紅燈" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="5dp">
<Button
android:id="@+id/lv"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="綠燈" />
<Button
android:id="@+id/blue"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="藍燈" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="5dp">
<Button
android:id="@+id/red_blue"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="紫燈" />
<Button
android:id="@+id/red_lv"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="黃燈" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="5dp">
<Button
android:id="@+id/lv_blue"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="青燈" />
<Button
android:id="@+id/red_lv_blue"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="橙燈" />
</LinearLayout>
<LinearLayout
android:layout_width="150dp"
android:layout_height="30dp"
android:layout_marginTop="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="蜂鳴器開關按鈕"
android:textSize="20sp" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="5dp">
<Button
android:id="@+id/fmq_on"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="開啟" />
<Button
android:id="@+id/fmq_off"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="關閉" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginTop="2dp"
android:layout_marginLeft="25dp"
android:layout_marginRight="25dp"
>
<TextView
android:id="@+id/New"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="5dp"
android:textColor="@color/紫羅蘭"
android:textSize="30dp"
/>
</LinearLayout>
</LinearLayout>
布局文件效果圖:
?別說了,我是ikun?。。。。?!其實當時想放打籃球的。
如果在布局文件里不更改themes.xml模塊代碼的話,這些按鍵的顏色只能是紫色,像下面這樣子,所以很影響各位家人的才華發(fā)展,起碼需要涂個黑色背帶褲。
所以我們需要打開項目下的values里面的themes.xml
?把 parent="Theme.MaterialComponents.DayNight.DarkActionBar"最后的DarkActionBar換成NoActionBar.Bridge,即parent="Theme.MaterialComponents.DayNight.NoActionBar.Bridge"
?這樣就可以隨意修改按鈕的背景顏色啦!
最后給大家個福利,就是幾個常用顏色的代碼,把這段代碼復制到valus文件下的colors.xml
代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="black">#FF000000</color>
<color name="white">#FFFFFFFF</color>
<color name="粉色">#FFC0CB</color>
<color name="紫羅蘭">#EE82EE</color>
<color name="靛青">#4B0082</color>
<color name="矢車菊的藍色">#6495ED</color>
<color name="適中的藍色">#0000CD</color>
<color name="深藍色">#00008B</color>
<color name="石板灰">#708090</color>
<color name="青色">#00FFFF</color>
<color name="猩紅">#DC143C</color>
<color name="軍校藍">#5F9EA0</color>
<color name="藍色">#0000FF</color>
<color name="水綠色">#00FFFF</color>
<color name="綠玉">#7FFFAA</color>
<color name="綠色">#00FF00</color>
<color name="黃色">#FFFF00</color>
<color name="橙紅色">#FF4500</color>
<color name="棕色">#A52A2A</color>
</resources>
4.Mainactivity
代碼如下:這是Mainactivity里面的全部代碼,建議不要全部復制進去,會出錯,按下面的方法慢慢敲,寫完感覺自己就懂得差不多,之所以發(fā)是因為下面的方法寫得有點亂了,所以發(fā)全部代碼出來。
package com.example.option;
import androidx.appcompat.app.AppCompatActivity;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.text.Html;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
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.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity {
public static MqttClient mMqClint;
private ScheduledExecutorService scheduler;
private MqttClient client;
private Handler handler;
private TextView temp_show;
private TextView mqtt_show;
private TextView led_show;
private TextView textView;
private String host = "tcp://mqtt.qzyuehua.cn"; // TCP協(xié)議
private String userName = "daluo";
private String passWord = "daluo1";
private String mqtt_id = "daluo2";
private String mqtt_sub_topic = "123456/stm32";
private String mqtt_pub_topic = "123456/app";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Mqtt_init();
startReconnect();
temp_show = findViewById(R.id.temp_tv);
mqtt_show = findViewById(R.id.m_mqtt);
led_show =findViewById(R.id.Light_status);
textView = (TextView)this.findViewById(R.id.New);
String html = "全民制作人們,大家好,我是練習時長兩年半的個人練習生蔡徐坤,喜歡唱、跳、rap、籃球,\n" +
" music!";
CharSequence charSequence = Html.fromHtml(html);
textView.setText(charSequence);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
textView.setSingleLine(true);
textView.setSelected(true);
textView.setFocusable(true);
textView.setFocusableInTouchMode(true);
Button button_off = (Button) findViewById(R.id.off);
button_off.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "關燈", Toast.LENGTH_SHORT).show();
publishmessageplus(mqtt_pub_topic, "L0");
led_show.setText("已關閉LED燈");
}
});
Button button_red = (Button) findViewById(R.id.red);
button_red.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "紅燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L1");
led_show.setText("紅燈");
}
});
Button button_lv = (Button) findViewById(R.id.lv);
button_lv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "綠燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L2");
led_show.setText("綠燈");
}
});
Button button_blue = (Button) findViewById(R.id.blue);
button_blue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "藍燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L3");
led_show.setText("藍燈");
}
});
Button button_red_blue = (Button) findViewById(R.id.red_blue);
button_red_blue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "紫燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L4");
led_show.setText("紫燈");
}
});
Button button_red_lv = (Button) findViewById(R.id.red_lv);
button_red_lv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "黃燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L5");
led_show.setText("黃燈");
}
});
Button button_lv_blue = (Button) findViewById(R.id.lv_blue);
button_lv_blue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "青燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L6");
led_show.setText("青燈");
}
});
Button button_red_lv_blue = (Button) findViewById(R.id.red_lv_blue);
button_red_lv_blue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "橙燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L7");
led_show.setText("橙燈");
}
});
Button fmq_ON = (Button) findViewById(R.id.fmq_on);
fmq_ON.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "打開蜂鳴器", Toast.LENGTH_SHORT).show();
publishmessageplus(mqtt_pub_topic, "L8");
led_show.setText("蜂鳴器已打開");
}
});
Button fmq_OFF = (Button) findViewById(R.id.fmq_off);
fmq_OFF.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "關閉蜂鳴器", Toast.LENGTH_SHORT).show();
publishmessageplus(mqtt_pub_topic, "L9");
led_show.setText("蜂鳴器已關閉");
}
});
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數(shù)據
break;
case 30: //連接失敗
//Toast.makeText(MainActivity.this, "連接成功", Toast.LENGTH_SHORT).
//show();
mqtt_show.setText("連接失敗!");
break;
case 31: //連接成功
Toast.makeText(MainActivity.this, "連接成功", Toast.LENGTH_SHORT).
show();
mqtt_show.setText("連接成功!");
try {
client.subscribe(mqtt_sub_topic, 1);
} catch (MqttException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
};
}
//mqtt初始化
private void Mqtt_init() {
try {
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秒的時間向客戶端發(fā)送個消息判斷客戶端是否在線,
// 但這個方法并沒有重連的機制
options.setKeepAliveInterval(20);
client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
System.out.println("connectionLost----------");
}
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
System.out.println("deliveryComplete---------"
+ iMqttDeliveryToken.isComplete());
}
@Override
public void messageArrived(String topicName, MqttMessage mqttMessage)
throws Exception {
final String payload = new String(mqttMessage.getPayload());
runOnUiThread(new Runnable() {
@Override
public void run() {
temp_show.setText(payload+"℃");
}
});
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
//MQTT連接函數(shù)
private void startReconnect() {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new Runnable(){
@Override
public void run() {
if (!client.isConnected()) {
Mqtt_connect();
}
}
},0*1000,10*1000, TimeUnit.MICROSECONDS);
}
//MQTT重新連接函數(shù)
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初始化
//訂閱函數(shù)
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();
}
}
private void Delay(){
if(mqtt_pub_topic!="L0"){
publishmessageplus(mqtt_pub_topic,"L0");
}
}
}
Mainactivity主要由以下幾個方法內容組成:
?onCreate里面主要是實現(xiàn)布局頁面按鈕的回調方法,這里也是比較容易犯錯的,手敲比較好。
(1)先寫需要用到的變量,代碼如下:
public static MqttClient mMqClint;
private MqttClient client;
private ScheduledExecutorService scheduler;
private Handler handler;
private TextView temp_show;
private TextView mqtt_show;
private TextView led_show;
private TextView textView;
然后就會報錯,把光標方到報紅的地方按住“Ait+回車”進行導包
?
?(2)mqtt配置代碼如下:
private String host = "tcp://mqtt.qzyuehua.cn"; // TCP協(xié)議,沒有的話也可以用我這個
private String userName = "admin";
private String passWord = "123456";
private String mqtt_id = "230722";
private String mqtt_sub_topic = "123456/stm32"; //發(fā)送方
private String mqtt_pub_topic = "123456/app"; //接收方
TCP協(xié)議的話大家也可以用我這個,是老師給的要是大家有自己的可以改。userName和passWord就是給mqtt.fx調試用的,但是我做實驗的時候壓根用不到,大家可寫進去也可不寫。剩下的三個都很重要的,尤其去發(fā)送方和接收方必須跟實驗板那邊的代碼一樣。
(3)OnCreate
先把下面這段代碼復制到OnCreate里面,代碼如下:
Mqtt_init();
startReconnect();
temp_show = findViewById(R.id.temp_tv);
mqtt_show = findViewById(R.id.m_mqtt);
led_show =findViewById(R.id.Light_status);
textView = (TextView)this.findViewById(R.id.New);
String html = "全民制作人們,大家好,我是練習時長兩年半的個人練習生蔡徐坤,喜歡唱、跳、rap、籃球\n" + "music!";
CharSequence charSequence = Html.fromHtml(html);
textView.setText(charSequence);
textView.setMovementMethod(LinkMovementMethod.getInstance());
textView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
textView.setSingleLine(true);
textView.setSelected(true);
textView.setFocusable(true);
textView.setFocusableInTouchMode(true);
然后有兩處需要加入兩個方法
?像上面一樣把光標放在報紅的代碼上,按住“AIT+回車”加入兩個方法:
?我們如果要寫實現(xiàn)點擊布局文件的按鈕,就有相應的變化,那么就要寫這些按鈕的點擊事件,我的布局頁面有很多個按鈕,所以相應點擊事件也很多,想看懂的記得結合一下布局文件各個按鈕的ID,這樣子就可以理解某個點擊事件所對應按鈕,也方便各位家人的自由發(fā)揮。
先把這段代碼復制粘貼進去:
Button button_off = (Button) findViewById(R.id.off);
button_off.setOnClickListener(new View.OnClickListener()
?然后把光標放在報錯的地方按住“AIT+回車”加入方法。
?
?然后再把下面的代碼復制粘貼到onClick里面:
Toast.makeText(MainActivity.this, "關燈", Toast.LENGTH_SHORT).show();
publishmessageplus(mqtt_pub_topic, "L0");
led_show.setText("已關閉LED燈");
這是關燈按鈕的點擊事件,我這么寫主要是為了讓大家知道怎么寫,如果全部復制進去就會報錯,方法必須手動建立。這里那個"publishmessageplus"會報錯,那是因為沒有建立這個方法,這個方法在最下面,這里沒有寫上,大家也不要理照樣寫下去,等到下面把publishmessageplus寫上去就不會報錯了。
其他按鈕的點擊事件的寫法也跟這個一模一樣,我就不贅述了,代碼如下:
Button button_red = (Button) findViewById(R.id.red);
button_red.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "紅燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L1");
led_show.setText("紅燈");
}
});
Button button_lv = (Button) findViewById(R.id.lv);
button_lv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "綠燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L2");
led_show.setText("綠燈");
}
});
Button button_blue = (Button) findViewById(R.id.blue);
button_blue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "藍燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L3");
led_show.setText("藍燈");
}
});
Button button_red_blue = (Button) findViewById(R.id.red_blue);
button_red_blue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "紫燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L4");
led_show.setText("紫燈");
}
});
Button button_red_lv = (Button) findViewById(R.id.red_lv);
button_red_lv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "黃燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L5");
led_show.setText("黃燈");
}
});
Button button_lv_blue = (Button) findViewById(R.id.lv_blue);
button_lv_blue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "青燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L6");
led_show.setText("青燈");
}
});
Button button_red_lv_blue = (Button) findViewById(R.id.red_lv_blue);
button_red_lv_blue.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "橙燈", Toast.LENGTH_SHORT).show();
Delay();
publishmessageplus(mqtt_pub_topic, "L7");
led_show.setText("橙燈");
}
});
Button fmq_ON = (Button) findViewById(R.id.fmq_on);
fmq_ON.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this, "打開蜂鳴器", Toast.LENGTH_SHORT).show();
publishmessageplus(mqtt_pub_topic, "L8");
led_show.setText("蜂鳴器已打開");
}
});
Button fmq_OFF = (Button) findViewById(R.id.fmq_off);
fmq_OFF.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(MainActivity.this, "關閉蜂鳴器", Toast.LENGTH_SHORT).show();
publishmessageplus(mqtt_pub_topic, "L9");
led_show.setText("蜂鳴器已關閉");
}
});
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數(shù)據
break;
case 30: //連接失敗
//Toast.makeText(MainActivity.this, "連接成功", Toast.LENGTH_SHORT).
//show();
mqtt_show.setText("連接失敗!");
break;
case 31: //連接成功
Toast.makeText(MainActivity.this, "連接成功", Toast.LENGTH_SHORT).
show();
mqtt_show.setText("連接成功!");
try {
client.subscribe(mqtt_sub_topic, 1);
} catch (MqttException e) {
e.printStackTrace();
}
break;
default:
break;
}
}
};
記住這些代碼全部寫在OnCreate()里面哦,不要寫在public class MainActivity extends AppCompatActivity{ }里面。
(4)Mqtt_init方法
代碼如下:
//mqtt初始化
private void Mqtt_init() {
try {
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秒的時間向客戶端發(fā)送個消息判斷客戶端是否在線,
// 但這個方法并沒有重連的機制
options.setKeepAliveInterval(20);
client.setCallback(new MqttCallback() {
@Override
public void connectionLost(Throwable cause) {
System.out.println("connectionLost----------");
}
@Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
System.out.println("deliveryComplete---------"
+ iMqttDeliveryToken.isComplete());
}
@Override
public void messageArrived(String topicName, MqttMessage mqttMessage)
throws Exception {
final String payload = new String(mqttMessage.getPayload());
runOnUiThread(new Runnable() {
@Override
public void run() {
temp_show.setText(payload+"℃");
}
});
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
(5)startReconnect方法
代碼如下:
//MQTT連接函數(shù)
private void startReconnect() {
scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(new Runnable(){
@Override
public void run() {
if (!client.isConnected()) {
Mqtt_connect();
}
}
},0*1000,10*1000, TimeUnit.MICROSECONDS);
}
(6)Mqtt_connect
代碼如下:
//MQTT重新連接函數(shù)
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();
}
(6)publishmessageplus方法
代碼如下:
//訂閱函數(shù)
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();
}
}
(7)Delay()方法
這個方法就是讓本次開燈時把上次開的燈關掉,如果不關的話就會串顏色,比如我第一次開的是紅燈,當我第二次按藍燈時,紅燈是不會自動關掉的,那么現(xiàn)在燈的狀態(tài)就是紅+藍的狀態(tài),所以每次都需要按關燈按鈕才可以打開其他燈,要不然會串顏色。因此我把關燈指令加在每個顏色燈指令前面,想開燈就先執(zhí)行關燈指令,其實這個方法很不好,大家用的時候就知道了,每次按顏色燈按鈕,都要發(fā)送兩個指令,如果stm32實驗板不好的話,只會接受到一個指令,也就是第一個關燈指令,所以要多按幾次,所以各位家人有好方法可以自己改改,并寫在評論區(qū)里面給大伙分享。
代碼如下:
private void Delay(){
if(mqtt_pub_topic!="L0"){
publishmessageplus(mqtt_pub_topic,"L0");
}
}
5、配置聯(lián)網權限
配置聯(lián)網權限很重要,一定要記得這串代碼寫進去,這個是決定APP能不能成功連接到mqtt服務器的關鍵
步驟:
(1)打開清單文件
?(2)把這串代碼粘貼進去manifest里面,代碼如下:
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<!--允許程序打開網絡套接字-->
<uses-permission android:name="android.permission.INTERNET" />
<!--允許程序獲取網絡狀態(tài)-->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
6.測試APP
到這里APP所有代碼都寫完成了,如果不報錯的話可以運行測試啦,出現(xiàn)以下界面證明運行成功。
?7.導出apk安裝包
如果想把APP安裝在手機上,那我們就要導出apk包
步驟:
(1)在菜單欄點擊Build,然后選擇Build Bundle/apk,最后點擊Build APK(s)。
?然后右下角會出現(xiàn)提示,我們點擊locate打開文件的保存地址
?進入文件管理頁面后,把apk安裝包發(fā)到手機進行安裝
?四、STM32實驗板代碼
stm32代碼太復雜了,整個代碼我也不是很理解,我是直接拿野火的實驗模版過來改一下,把要用到的user文件全部導進去,所以我直接把keil5代碼整個打包放在百度網盤里面,你們自行下載然后在keil5打開就可以了,下面我就介紹幾個需要用到的地方和可以更改的地方,以及某個代碼塊是干什么的,有什么作用,也方便各位的使用。
鏈接:https://pan.baidu.com/s/1J5rJXD4bAuc6kYcv961fmg?pwd=rps1?
提取碼:rps1
網盤里面有四個文件?。。。。。。。。。。。。。。。。。。。?!
第一個文件有野火的很多實驗案列,對于想學習STM32的同學可以打開試試,現(xiàn)在說的是第四個,它就是stm32的實驗板代碼,下載解壓然后在keil5 MDK直接打開就可以用了。以下我逐個介紹用到的代碼:
1.main函數(shù)
main函數(shù)里面值得改的就是我圈的這里,這里就是發(fā)送者和接收者,這里要跟app里面的一致,其他的大家感興趣的話看著來慢慢研究。
?
2.esp8266
這個函數(shù)主要用于給實驗板連接手機熱點和mqtt服務器?。。。。。?!
想實現(xiàn)物聯(lián)網的話, STM32實驗班和APP都必須同時連上網,所以實驗板必須要連接我們自己的手機熱點或者其他可以上網的網絡。把第一個define里面的“WIFI Name ”改成自己手機的熱點名,“WIFI password”改成熱點密碼,到時候把代碼寫進去STM32實驗板后會自動連接手機熱點。
?3.onenet
這個函數(shù)主要是負責的接收APP那邊發(fā)送來的指令然后發(fā)送給實驗板做出相應反應,上面我們寫那個安卓APP的時候,你們可以看到每個按鈕的點擊事件里面有L0,L1,L2等就是對應這里,L0對應的是三個基色等全部關閉,三基色燈不同打開方式的組合形成了另外四種燈,有什么新的指令大家就在這里加,這個函數(shù)主要是負責接收APP那邊發(fā)送過來的指令。
?4.小總結
五、測試
1.測試app與mqtt的連接狀態(tài)
(1)安裝mqtt.fx并打開
?打開后是以下界面,Publish是發(fā)送方,Subscribe訂閱方,如果想知道其他用法大家自己去百度吧,我也不想贅述了,這里我就講這這個實驗用到的內容。剛剛開始可以有點不理解,但是用久了自然就明白,這個其實就是測試APP能否連接到mqtt服務器,以及檢查指令是否發(fā)送到mqtt服務器。
(2) 配置mqtt.fx的參數(shù)
點擊設置進去配置頁面
?配置情況如下:
?確定后回到主頁面,點擊Connect進行連接
?右上角出現(xiàn)綠燈說明連接成功連接成功
?在發(fā)布選項框下輸入“123456/stm32”,然后在下面的空白框中輸入溫度發(fā)送給app進行顯示。
如下圖,我發(fā)送了一個為數(shù)值為35的溫度主題,可以看到app訂閱到了。?
在Sublime輸入123456/app,?點擊app的容易一個按鈕,123456/app也訂閱到了app發(fā)送過來的指令,到了這一步,證明app已經完成了。
2.將app與實驗板同時連接mqtt服務器,實現(xiàn)遠程控制
因為這個文章我是在宿舍寫的,也沒有那個實驗板,所以這里我就沒有圖片展示了,大家多多見諒。
步驟:
(1)在keil上把代碼寫入實驗板,并打開app和串口調試助手(網盤第二個文件),選擇好端口然后打開串口調試,記得打開WIFI給實驗進行連接。
?出現(xiàn)以下界面,證明連接成功?。。。?!
?開始進行我們的第一個物聯(lián)網實驗吧?。。。?!
?視頻解析:
視頻解析
?六、總結
這個實驗就是讓開發(fā)的app和F103實驗板通過mqtt的IP協(xié)議同時連接上mqtt服務器實現(xiàn)遠程控制,app先把指令發(fā)送到mqtt服務器,mqtt服務器接到指令再發(fā)送給實驗板,實驗板也通過mqtt服務器將溫度發(fā)送給APP,這期間mqtt充當著中介的角色。我的專業(yè)發(fā)展主要是往Java方向,所以對硬件方面也不是很懂,這個實驗也是做得稀里糊涂,如果大家有不明白的,可以把問題寫在評論區(qū),我看到會回復,但不敢保證所有問題都能解決,畢竟我也是個二把刀。也要感謝CSDN的這位作者:文章來源:http://www.zghlxwxcb.cn/news/detail-751550.html
我app的代碼,大部分也都是參考他的,你們要是看不懂我寫的,可以去看看他的,他寫得比較詳細,也解釋得清楚點。文章來源地址http://www.zghlxwxcb.cn/news/detail-751550.html
到了這里,關于一個小型的物聯(lián)網實驗,讓stm32實驗板和Android studio寫的APP同時連接上mqtt服務器實現(xiàn)遠程控制實驗板狀態(tài)的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!