如果不了解MQTT的可以看這篇文章 http://www.cnblogs.com/yangfengwu/p/7764667.html
http://www.cnblogs.com/yangfengwu/p/8026014.html
如果看不懂也沒關系,跟着做就可以了,做完以后您會發現原來MQTT這么好用,也如此簡單.
對了我要盡量把程序寫的爛一些,界面做的爛一些,因為既然是學習用的應該越直觀越好.......說一下,自己的服務器因為公開了穩定性上肯定不好,
數據沖突也是可能的,這是第一篇,下面幾篇慢慢的來,咱一塊慢慢完善哈
實現的功能--手機和WIFI模塊都連接MQTT服務器,手機用按鈕實現遠程控制一個繼電器,然后WIFI模塊采集的DHT11的溫濕度,遠程發給手機
不過自己這批貼片的板子要等到后天才到..........................



先看一下Android 程序怎么寫,首先就是下載個MQTT的jar包
鏈接:https://pan.baidu.com/s/1bpjRzyB 密碼:90vv
新建一個Android 工程就不說了吧...............
將下載的jar包放在一個地方

我放在了我的Android的源碼的根目錄
現在在Android 工程導入下載的那個jar包





現在把可能用到的一些權限加上

<!-- 獲取手機信息權限 -->
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" ></uses-permission>"
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"></uses-permission>
<uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"></uses-permission>
現在呢先寫個程序獲取手機的IMEI號,因為連接的時候每一個客戶端的ClientID要求不能一樣,咱就用IMEI號代表ClientID

其實就這兩句
TelephonyManager mTm = (TelephonyManager)this.getSystemService(TELEPHONY_SERVICE); TelephonyIMEI = mTm.getDeviceId();
現在配置咱的MQTT
public class MainActivity extends Activity { String TelephonyIMEI=""; private MqttClient client;//client private MqttConnectOptions options;//配置 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TelephonyManager mTm = (TelephonyManager)this.getSystemService(TELEPHONY_SERVICE); TelephonyIMEI = mTm.getDeviceId(); //Toast.makeText(getApplicationContext(), TelephonyIMEI, 500).show(); MyMqttInit(); } /* 初始化配置Mqtt */ private void MyMqttInit() { try { //(1)主機地址(2)客戶端ID,一般以客戶端唯一標識符(不能夠和其它客戶端重名)(3)最后一個參數是指數據保存在內存(具體保存什么數據,以后再說,其實現在我也不是很確定) client = new MqttClient("tcp://47.93.19.134:1883",TelephonyIMEI,new MemoryPersistence()); } catch (MqttException e) { // TODO Auto-generated catch block e.printStackTrace(); } options = new MqttConnectOptions();//MQTT的連接設置 options.setCleanSession(true);//設置是否清空session,這里如果設置為false表示服務器會保留客戶端的連接記錄,這里設置為true表示每次連接到服務器都以新的身份連接 options.setUserName("username");//設置連接的用戶名(自己的服務器沒有設置用戶名) options.setPassword("password".toCharArray());//設置連接的密碼(自己的服務器沒有設置密碼) options.setConnectionTimeout(10);// 設置連接超時時間 單位為秒 options.setKeepAliveInterval(20);// 設置會話心跳時間 單位為秒 服務器會每隔1.5*20秒的時間向客戶端發送個消息判斷客戶端是否在線,但這個方法並沒有重連的機制 client.setCallback(new MqttCallback() { @Override//獲取的消息會執行這里--arg0是主題,arg1是消息 public void messageArrived(String arg0, MqttMessage arg1) throws Exception { // TODO Auto-generated method stub } @Override//訂閱主題后會執行到這里 public void deliveryComplete(IMqttDeliveryToken arg0) { // TODO Auto-generated method stub } @Override//連接丟失后,會執行這里 public void connectionLost(Throwable arg0) { // TODO Auto-generated method stub } }); }
現在連接咱的服務器,連接成功后打印一下連接成功,連接是阻塞的,所以放在一個任務里面執行連接
public class MainActivity extends Activity { String TelephonyIMEI=""; private MqttClient client;//client private MqttConnectOptions options;//配置 MqttConnectThread mqttConnectThread = new MqttConnectThread();//連接服務器任務 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TelephonyManager mTm = (TelephonyManager)this.getSystemService(TELEPHONY_SERVICE); TelephonyIMEI = mTm.getDeviceId(); //Toast.makeText(getApplicationContext(), TelephonyIMEI, 500).show(); MyMqttInit();//初始化配置MQTT客戶端 mqttConnectThread.start();//執行連接服務器任務 } /* 初始化配置Mqtt */ private void MyMqttInit() { ......... } /*連接服務器任務*/ class MqttConnectThread extends Thread { public void run() { try { client.connect(options);//連接服務器,連接不上會阻塞在這 runOnUiThread(new Runnable() {// public void run() { Toast.makeText(getApplicationContext(), "連接成功", 500).show(); } }); } catch (MqttSecurityException e) { //安全問題連接失敗 } catch (MqttException e) { //連接失敗原因 } } }
現在下載到手機試一試

現在呢測試一下通信,測試接收消息,用調試助手發信息,然后手機端接收,然后顯示出來
調試助手鏈接
鏈接:https://pan.baidu.com/s/1qYxEeLI 密碼:exfj
現在先設置一下APP的訂閱的主題,和接收到消息之后就顯示出來


public class MainActivity extends Activity { String TelephonyIMEI=""; private MqttClient client;//client private MqttConnectOptions options;//配置 MqttConnectThread mqttConnectThread = new MqttConnectThread();//連接服務器任務 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TelephonyManager mTm = (TelephonyManager)this.getSystemService(TELEPHONY_SERVICE); TelephonyIMEI = mTm.getDeviceId(); //Toast.makeText(getApplicationContext(), TelephonyIMEI, 500).show(); MyMqttInit();//初始化配置MQTT客戶端 mqttConnectThread.start();//執行連接服務器任務 } /* 初始化配置Mqtt */ private void MyMqttInit() { try { //(1)主機地址(2)客戶端ID,一般以客戶端唯一標識符(不能夠和其它客戶端重名)(3)最后一個參數是指數據保存在內存(具體保存什么數據,以后再說,其實現在我也不是很確定) client = new MqttClient("tcp://47.93.19.134:1883",TelephonyIMEI,new MemoryPersistence()); } catch (MqttException e) { // TODO Auto-generated catch block e.printStackTrace(); } options = new MqttConnectOptions();//MQTT的連接設置 options.setCleanSession(true);//設置是否清空session,這里如果設置為false表示服務器會保留客戶端的連接記錄,這里設置為true表示每次連接到服務器都以新的身份連接 options.setUserName("username");//設置連接的用戶名(自己的服務器沒有設置用戶名) options.setPassword("password".toCharArray());//設置連接的密碼(自己的服務器沒有設置密碼) options.setConnectionTimeout(10);// 設置連接超時時間 單位為秒 options.setKeepAliveInterval(20);// 設置會話心跳時間 單位為秒 服務器會每隔1.5*20秒的時間向客戶端發送個消息判斷客戶端是否在線,但這個方法並沒有重連的機制 client.setCallback(new MqttCallback() { @Override//獲取消息會執行這里--arg0是主題,arg1是消息 public void messageArrived(String arg0, MqttMessage arg1) throws Exception { // TODO Auto-generated method stub final String topic = arg0;//主題 final String msgString = arg1.toString();//消息 runOnUiThread(new Runnable() {// public void run() { Toast.makeText(getApplicationContext(),"主題:"+topic+"消息:"+msgString, 500).show(); } }); } @Override//訂閱主題后會執行到這里 public void deliveryComplete(IMqttDeliveryToken arg0) { // TODO Auto-generated method stub } @Override//連接丟失后,會執行這里 public void connectionLost(Throwable arg0) { // TODO Auto-generated method stub } }); } /*連接服務器任務*/ class MqttConnectThread extends Thread { public void run() { try { client.connect(options);//連接服務器,連接不上會阻塞在這 client.subscribe("test",0);//設置(訂閱)接收的主題,主題的級別是0 runOnUiThread(new Runnable() {// public void run() { Toast.makeText(getApplicationContext(), "連接成功", 500).show(); } }); } catch (MqttSecurityException e) { //安全問題連接失敗 } catch (MqttException e) { //連接失敗原因 } } }
下載到手機
現在配置一下軟件,對了有些參數現在不明白沒關系,后面會介紹一下相關的知識,

軟件的主題名稱要和APP中訂閱的主題一樣 都是 test
現在連接

現在點擊發布消息

看手機端

說明已經能通信了
現在說一下關於主題哈,關於/
現在把手機端的訂閱的主題改為"/#"

然后下載到手機


你會發現手機也能接收消息


手機都能接收到消息
# 是一個匹配主題中任意層次數的通配符。比如說,如果你訂閱了test/device/#,你就可以接收到以下這些主題的消息。
test/device
test/device/后面隨便是什么
咱們的設備可以用"/"來進行分類,咱們的APP呢可以指定接收哪一類的產品的數據"XXXX/#"....是不是很方便
對了如果現在接收兩個已知主題的設備
假如說是

第一種方式


第二種方式

結果和上面一樣

現在呢在界面加一個按鈕,按下發送消息"1",松開發送消息"0"
然后設置發布的主題是"/test/button"



public class MainActivity extends Activity { String TelephonyIMEI=""; private MqttClient client;//client private MqttConnectOptions options;//配置 MqttConnectThread mqttConnectThread = new MqttConnectThread();//連接服務器任務 Button button;//發送消息按鈕 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); button = (Button) findViewById(R.id.button1);//獲取發送消息按鈕 button.setOnTouchListener(buttonTouch);//設置按鈕的觸摸事件 TelephonyManager mTm = (TelephonyManager)this.getSystemService(TELEPHONY_SERVICE); TelephonyIMEI = mTm.getDeviceId(); //Toast.makeText(getApplicationContext(), TelephonyIMEI, 500).show(); MyMqttInit();//初始化配置MQTT客戶端 mqttConnectThread.start();//執行連接服務器任務 } /*按鈕觸摸事件*/ private OnTouchListener buttonTouch = new OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { MqttMessage msgMessage = null;//Mqtt消息變量 if (event.getAction() == MotionEvent.ACTION_DOWN) //按下 { msgMessage = new MqttMessage("1".getBytes()); } else if (event.getAction() == MotionEvent.ACTION_UP) //松開 { msgMessage = new MqttMessage("0".getBytes()); } try { client.publish("/test/button",msgMessage);//發送主題為"/test/button"的消息 } catch (MqttPersistenceException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (MqttException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (Exception e) { //其余的狀態msgMessage = null;所以加了這個catch (Exception e) } return false; } };
現在下載到手機,
調試助手訂閱一下主題 "/test/button"

動作一下按鈕


現在把發過來的數據用文本框顯示,不讓他提示了


接收顯示的換一下

runOnUiThread(new Runnable() {//因為操作的是主界面的控件所以用刷新UI的線程,最好用handle哈,我這里怎么簡單怎么寫 public void run() { //Toast.makeText(getApplicationContext(),"主題:"+topic+"消息:"+msgString, 500).show(); textView.setText("主題:"+topic+"\n消息:"+msgString); } });
現在試一下


好了,現在咱開始控制咱的WIFI模塊了....用咱的手機控制WIFI板子上的繼電器,WIFI模塊呢采集溫濕度,然后顯示在手機的文本框中
自己更傾向於用lua開發,所以要刷入lua的固件哈
關於刷固件可以參考
http://www.cnblogs.com/yangfengwu/p/7514336.html
自己已經下載好的固件
鏈接:https://pan.baidu.com/s/1o8pAISy 密碼:9zns
如果親們自己下載的話別忘了,把mqtt和dht選擇上哈

程序--init.lua
wifi.setmode(wifi.STATION) RelayPin = 2;--RelayPin gpio.mode(RelayPin,gpio.OUTPUT)--RelayPin gpio.write(RelayPin,0)--RelayPin LedPin = 4;--LedPin gpio.mode(LedPin,gpio.OUTPUT)--LedPin gpio.write(LedPin,0)--LedPin DHT11pin = 5--DHT11 GPIO Temperature = "0";--Storage temperature Humidity = "0";--Store humidity apcfg={} apcfg.ssid="qqqqq" apcfg.pwd="11223344" wifi.sta.config(apcfg) --wifi.sta.connect() wifi.sta.autoconnect(1) clientid = wifi.sta.getmac() mqttClient=nil mqttConnectedFlage = 0; Mymqtt = mqtt.Client(clientid, 120,"user", "password"); --[[The connection serve]] tmr.alarm(0, 1000, 1, function() Mymqtt:connect("47.93.19.134", 1883, 0,ConnectSuccess,ConnectFailed) end) --[[The connection Success]] function ConnectSuccess(client) client:subscribe("/test/button", 0, subscribeSuccess) print("connected") mqttClient = client; tmr.stop(0); mqttConnectedFlage = 1; end --[[The connection fails]] function mqttConnectFailed(client,reason) mqttConnectedFlage = 0; print("failed reason: " .. reason) tmr.start(0); end --[[The subscribe Success]] function subscribeSuccess(client) print("subscribe success") end --[[The Receive Msg]] Mymqtt:on("message", function(client, topic, data) if string.find(data,"1") ~= nil then gpio.write(RelayPin,1) end if string.find(data,"0") ~= nil then gpio.write(RelayPin,0) end end) --[[The Send Msg]] tmr.alarm(1, 1000, 1, function() if mqttClient ~= nil and mqttConnectedFlage == 1 then mqttClient:publish("/test/yang","Temperature="..Temperature..";".."Humidity="..Humidity, 0, 0, function(client) gpio.write(4,1-gpio.read(4)) end) end end) --[[The gather humiture data]] tmr.alarm(5, 2000, 1, function()--Every other 1S local status, temp, humi, temp_dec, humi_dec = dht.read11(DHT11pin)--Gathering temperature and humidity if status == dht.OK or status == dht.ERROR_CHECKSUM then Temperature = temp; Humidity = humi; --print("DHT Temperature:"..temp..";".."Humidity:"..humi) end end) printip = 0 wifi.eventmon.register(wifi.eventmon.STA_DISCONNECTED, function(T) printip = 0 end) wifi.eventmon.register(wifi.eventmon.STA_GOT_IP, function(T) if printip == 0 then ip,netmask,gateway = wifi.sta.getip() print(gateway) end printip = 1 end)
現在說一下個個部分的功能,對了關於語法問題和其余的問題就請大家參考我的,其實上面的代碼就是參考的官方給的API函數,
我希望親們最重要的是有自學的能力,而不是需要別人灌輸東西的機器.









好了親們可以自己去測試了
源碼和資料鏈接
鏈接:https://pan.baidu.com/s/1xLv1VB2yiqQJeTb1vDB6kQ 密碼:5jzd
wifi的就是上面的,直接復制粘貼過去就好啦
