zoukankan      html  css  js  c++  java
  • (一)基于阿里云的MQTT远程控制(Android 连接MQTT服务器,ESP8266连接MQTT服务器实现远程通信控制----简单的连接通信)

    如果不了解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+"
    消息:"+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的就是上面的,直接复制粘贴过去就好啦

  • 相关阅读:
    软工实践寒假作业(1/2)
    java判断是否为数字
    前端测试工具Cypress
    StringBuffer&StringBuilder
    IO流
    kafka简介
    Python学习笔记10--unittest参数化
    python学习笔记9--日志模块logging
    Python学习笔记9-多线程和多进程
    python学习笔记9-单元测试unittest
  • 原文地址:https://www.cnblogs.com/yangfengwu/p/8175080.html
Copyright © 2011-2022 走看看