外網遠程控制LED小燈的實現

注:該項目參考自Arduino中文社區kevinzhang19701樓主的帖子
:小題大做之遠程LED控制
http://www.arduino.cn/forum.php?mod=viewthread&tid=8463&fromuid=84650
(出處: Arduino中文社區)
在這裏十分感謝這位老師。
我覺得這個很有潛力,控制LED小燈只是開始,有了這個基本的項目,就可以拓展爲外網遠程控制其他一些家庭電器,儼然可以成爲智能家居的一個切入點。

1預備工作:

1.由於需要可以通過外網來控制小燈,所以內網穿透是必不可少的。
我們選擇了花生殼來實現。
首先要找到花生殼官網(Oray)進行註冊,然後你會獲得一個免費的域名,這個免費的域名的長相十分奇怪不容記憶,但是免費送的並且僅僅只是實驗測試用的所以就不要抱怨了。(當然你可以升級爲付費版商業版的,域名端口都可以定製)
得到域名之後需要開啓內網穿透服務,建議不想花費太多的話可以開啓免費版(但是開通還是需要繳納少量的費用)。我用的就是免費版的服務,足夠這個項目用的。有一點需要注意,免費版的服務解析速度偏慢,而且有流量限制(每月1G),所以呢,網頁如果需要加載很多圖片視頻的話,那麼就得考慮升級個人商業版了。建議一切從簡,學到原理最重要。
2.準備一臺電腦來作爲服務器。
當然實驗階段的話,可以用自己的筆記本或者一臺二手舊電腦,不用擔心性能,對這個實驗項目古董電腦都綽綽有餘了。(當然土豪就當我什麼都沒說,直接去某寶買專業的服務器或者工作站好了,至於工作站或者服務器的使用和配置方法去問度娘吧)

2硬件部分:

1.控制器部分:Arduino UNO R3 開發板

2.Ethernet W5100

這裏寫圖片描述

3.導線,麪包板,200歐(或者1K歐姆)的電阻兩個,兩個LED,路由器,網線

這裏寫圖片描述

4.兩件疊加效果圖:

這裏寫圖片描述

5.接線效果圖:

這裏寫圖片描述

3軟件部分:

(默認JAVA開發環境已經配置好了,沒有配好JAVA環境先配置環境)
1.Arduino IDE:
下載鏈接:https://yunpan.cn/cMjJIsprnQbad 訪問密碼 f834
Arduino IDE的安裝十分簡單不再多說了。
2.Tomcat:
下載鏈接:https://yunpan.cn/cMjJTDtkc8UDb 訪問密碼 fe5c
Tomcat也需要配置環境變量哦
3.MySQL:
下載鏈接:https://yunpan.cn/cMjJC35LDecxx 訪問密碼 071f
4.MySQL Workbench:
下載鏈接:https://yunpan.cn/cMjJ7bb4rPzJI 訪問密碼 b6d7
Workbench這個軟件是搭配MySQL來使用的,它是MySQL的圖形界面
5.eclipse jee:
下載鏈接:https://yunpan.cn/cMjZyfFRnfgCi 訪問密碼 0ac4
6.JDBC:
下載鏈接:https://yunpan.cn/cMjVsNUAMetP3 訪問密碼 4ad5
6.花生殼客戶端:
下載鏈接:https://yunpan.cn/cMjZVw8hqcd33 訪問密碼 052e

4邏輯部分:

邏輯應該很清楚了:客戶端可以通過外網訪問到服務器,
服務器上有兩個servlet:ControlServletResponseServlet
ControlServlet:主要接受來自於外網訪客對LED開/關狀態的變化,並要將這些變化狀態寫入MySQL數據庫(對應0和1)
ResponseServlet:主要是回答W5100每隔1秒向服務器提交的LED狀態查詢。
然後
Arduino板子上的sketch只完成一個工作:
每隔1秒向服務器查詢數據庫裏最新的LED狀態,然後刷新LED高低電平。

5代碼部分:

Arduino代碼:

 #include <SPI.h>
#include <Ethernet.h>
byte mac[]    = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
IPAddress dnserver(192, 168, 0,105);
IPAddress     ip(192, 168,0,111);
EthernetClient client;
char c;
String result;
void setup() {
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
  delay(3000);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  Serial.println("Ethernet connecting...");

}

void loop() {
  if (client.connect(dnserver, 80)) 
  {
      Serial.println("Connected");
      client.println("POST http://192.168.0.105:80/remoteControlByYuancong/ResponseServlet HTTP/1.1");
      client.println("Host:192.168.0.105");
      client.println();
      delay(1000);
     // Serial.println(client.available());//爲什麼返回值比實際的字符串長度多2?
       while(client.available())
       {
        c = client.read();
        result += c;
       }
       //Serial.println("==");
       Serial.println(result.substring(0,156));
       Serial.println(result.substring(147,156));
       Serial.println(result.substring(147,151));
      if (result.substring(147,151).equals("A2=1"))
      {
        digitalWrite(2, HIGH);
      }
      else
      {
        digitalWrite(2, LOW);
      }
      if (result.substring(152,156).equals("A3=1"))
      {
        digitalWrite(3, HIGH);
      }
      else
      {
        digitalWrite(3, LOW);
      }
    client.stop();
    result = "";
  } 


  else 
  {
    Serial.println("connection failed");
  }


}

web代碼:

<!DOCTYPE html>
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>遙控</title>
<style type="text/css">

body{
    margin:0px;
    text-align:center;    /*居中*/
}

div{
    box-sizing:border-box;          /*盒子寬高設置以border爲標準*/
}

#top{
    height:50px;         
    margin:0 auto ;
}
.container{
    width:270px;
    height:480px;
    margin:0 auto;
    background-color:#FFFFFF;
    background-image:url("images/76.jpg");
    <!--border-radius:10px;-->
    border-style:solid; 
    border-width:2px; 
    border-color:gray;
    box-shadow:5px 5px 5px gray;

}
.className{
  line-height:50px;
  height:50px;
  width:180px;
  color:#ffffff;
  background-color:#f78d12;
  font-size:17px;
  font-weight:normal;
  font-family:Arial;
  border:3px solid #3d465e;
  -webkit-border-top-left-radius:40px;
  -moz-border-radius-topleft:40px;
  border-top-left-radius:40px;
  -webkit-border-top-right-radius:40px;
  -moz-border-radius-topright:40px;
  border-top-right-radius:40px;
  -webkit-border-bottom-left-radius:40px;
  -moz-border-radius-bottomleft:40px;
  border-bottom-left-radius:40px;
  -webkit-border-bottom-right-radius:40px;
  -moz-border-radius-bottomright:40px;
  border-bottom-right-radius:40px;
  -moz-box-shadow: inset 0px 0px 0px 0px #ffffff;
  -webkit-box-shadow: inset 0px 0px 0px 0px #ffffff;
  box-shadow: inset 0px 0px 0px 0px #ffffff;
  text-align:center;
  display:inline-block;
  text-decoration:none;
}.className:hover{
  background-color:#f8cd04;
}

#login{
width:270px;
height:202px;
background-color:;

}
#twopart{
    width:360;
    height:16px;
    background-color:;

}
input.ys{
color: #ffffff;
height: 30px;
background-color: #f78d12;
}

</style>
<link rel="shortcut icon" href="xiaoTuBiao.ico" type="image/x-icon" />
</head>
<body>
<script LANGUAGE = "JavaScript" >
 function checkvalue()
 {
 alert('已提交');
 return true;

 } </script>

<div id="top"></div>
<div class="container" >
<p style="color:#ffffff;font-size:20px"></p>
<br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>

<div id="login">
<form name='form1'action="http://15440a9z84.iask.in:41498/remoteControlByYuancong/ControlServlet?p=1" method="post" >
<a href='javascript:document.form1.submit();' class='className' onclick="checkvalue()">開啓遙控器</a>
</form>
</div>
<a href="index.html">返回主頁</a>
</div>
</body>
</html>

ControlServlet:

package remoteControlByYuancong;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.mysql.jdbc.Connection;
import com.mysql.jdbc.Statement;

/**
 * Servlet implementation class ContronlServlet
 * 這個進行主要功能操作
 */
@WebServlet("/ControlServlet")
public class ControlServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */

    public ControlServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException 
    {
        response.setContentType("text/html;charset=UTF-8");

        String p=request.getParameter("p"); 

//request.getParameter()方法是用來獲取URL中的參數的
        String a2 = "0";
        String a3 = "0";
        String n  = "0";

        String a2s = "0";
        String a3s = "0";

        Connection conn = null;
        Statement stmt = null;
        ResultSet rs1 = null;
        int s=0;
        try (PrintWriter out = response.getWriter()) 
        {
            if (p.equals("1"))
            {
                try
                {
                    Class.forName("com.mysql.jdbc.Driver");
                    System.out.println("成功加載數據庫");
                    conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata","root" ,"521314");
                    stmt = (Statement) conn.createStatement();
                    System.out.println("正在");
                    System.out.println("查詢最後一條記錄...");
                    rs1 = stmt.executeQuery("SELECT * FROM t1 ORDER BY aid DESC LIMIT 1;");
                    System.out.println("完成");

                    while(rs1.next())
                    {
                        n = rs1.getString(2);//第二列
                        if (n.equals("1"))
                        {
                            a2s = "1";
                        }
                        else
                        {
                            a2s = "0";
                        }
                        n = rs1.getString(3);
                        if (n.equals("1"))
                        {
                            a3s = "1";
                        }
                        else
                        {
                            a3s = "0";
                        }

                    }

                }

                catch (SQLException ex) 
                {
                    System.out.println("Error in connection: " + ex.toString());
                    System.out.println("SQLException: " + ex.getMessage());
                    System.out.println("SQLState: " + ex.getSQLState());
                    System.out.println("VendorError: " + ex.getErrorCode());
                } catch (ClassNotFoundException e) {
                    // TODO 自動生成的 catch 塊
                    e.printStackTrace();
                } 
                /* TODO output your page here. You may use following sample code. */
                out.println("<!DOCTYPE html>");
                out.println("<html>");
                out.println("<head>");
                out.println("<title>Remote Controlled LEDs.</title>");
                out.println("<meta charset=\"UTF-8\">");
                out.println("</head>");
                out.println("<body onLoad=\"setForm();\">");
                out.println("<br><br>");
                out.println("巨醜遙控器");
                out.println("<form id=\"f1\" method=\"POST\" action=\"http://15440a9z84.iask.in:41498/remoteControlByYuancong/ControlServlet?p=2\">");
                out.println("<table align=\"center\" border=\"1\">");
                out.println("<tr>");
                out.println("<td>A2:</td>");
                if (a2s.equals("0"))
                {
                    out.println("<td><input type=\"radio\" name=\"a2\" value=\"0\" checked>Off</td>");
                    out.println("<td><input type=\"radio\" name=\"a2\" value=\"1\">On</td>");
                }
                else
                {
                    out.println("<td><input type=\"radio\" name=\"a2\" value=\"0\">Off</td>");
                    out.println("<td><input type=\"radio\" name=\"a2\" value=\"1\" checked>On</td>");
                }
                out.println("</tr>");
                out.println("<tr>");
                out.println("<td>A3:</td>");
                if (a3s.equals("0"))
                {
                    out.println("<td><input type=\"radio\" name=\"a3\" value=\"0\" checked>Off</td>");
                    out.println("<td><input type=\"radio\" name=\"a3\" value=\"1\">On</td>");
                }
                else
                {
                    out.println("<td><input type=\"radio\" name=\"a3\" value=\"0\">Off</td>");
                    out.println("<td><input type=\"radio\" name=\"a3\" value=\"1\" checked>On</td>");
                }
                out.println("</tr>");
                out.println("<tr>");
                out.println("<td colspan=\"3\" align=\"center\"><input type=\"submit\" value=\"確認\"></td>");
                out.println("</tr>");
                out.println("</table>");
                out.println("</form>");
                out.println("</body>");
                out.println("</html>");
                //System.out.println("aaa");
            }


            else
            {
                if (!request.getParameter("a2").equals("1"))
                {
                    a2 = "0";
                }
                else
                {
                    a2 = "1";
                }
                if (!request.getParameter("a3").equals("1"))
                {
                    a3 = "0";
                }
                else
                {
                    a3 = "1";
                }


                try
                {

                    conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost:3306/mydata","root" ,"521314");
                    stmt = (Statement) conn.createStatement();
                    System.out.println("正在");
                    System.out.println("追加記錄......");
                    s = stmt.executeUpdate("INSERT INTO t1 (a2,a3) VALUES ('"
                            + a2 + "','"
                            + a3 + "')");
                    System.out.println("完成");
                    //這個s只是起到了一個儲存返回值的作用,但是對這個返回值的操作,原來的代碼並沒有寫
                    //也因此IDE檢測到這個s沒有使用過所以給了警報

                }
                catch (SQLException ex) 
                {
                    System.out.println("Error in connection: " + ex.toString());
                    System.out.println("SQLException: " + ex.getMessage());
                    System.out.println("SQLState: " + ex.getSQLState());
                    System.out.println("VendorError: " + ex.getErrorCode());
                }
                /* TODO output your page here. You may use following sample code. */
//應該是生成了一個新的頁面吧
                out.println("<!DOCTYPE html>");
                out.println("<html>");
                out.println("<head>");
                out.println("<title>Remote Controlled LEDs.</title>");
                out.println("<meta charset=\"UTF-8\">");
                out.println("</head>");
                out.println("<body onLoad=\"setForm();\">");
                out.println("<br><br>");
                out.println("<form id=\"f1\" method=\"POST\" action=\"http://15440a9z84.iask.in:41498/remoteControlByYuancong/ControlServlet?p=2\">");
                out.println("<table align=\"center\" border=\"1\">");
                out.println("<tr>");
                out.println("<td>A2:</td>");
                if (a2.equals("0"))
                {
                    out.println("<td><input type=\"radio\" name=\"a2\" value=\"0\" checked>Off</td>");
                    out.println("<td><input type=\"radio\" name=\"a2\" value=\"1\">On</td>");
                }
                else
                {
                    out.println("<td><input type=\"radio\" name=\"a2\" value=\"0\">Off</td>");
                    out.println("<td><input type=\"radio\" name=\"a2\" value=\"1\" checked>On</td>");
                }
                out.println("</tr>");
                out.println("<tr>");
                out.println("<td>A3:</td>");
                if (a3.equals("0"))
                {
                    out.println("<td><input type=\"radio\" name=\"a3\" value=\"0\" checked>Off</td>");
                    out.println("<td><input type=\"radio\" name=\"a3\" value=\"1\">On</td>");
                }
                else
                {
                    out.println("<td><input type=\"radio\" name=\"a3\" value=\"0\">Off</td>");
                    out.println("<td><input type=\"radio\" name=\"a3\" value=\"1\" checked>On</td>");
                }
                out.println("</tr>");

                out.println("<tr>");
                out.println("<td colspan=\"3\" align=\"center\"><input type=\"submit\" value=\"確認\"></td>");
                out.println("</tr>");
                out.println("</table>");
                out.println("</form>");
                out.println("</body>");
                out.println("</html>");

            }
        }
    }






    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        processRequest(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub
        processRequest(request, response);

    }

}

ResponseServlet:

package remoteControlByYuancong;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.mysql.jdbc.Connection;
import com.mysql.jdbc.Statement;
/**
 * Servlet implementation class ResponseServlet
 * 這裏寫回答Arduino板子的servlet
 */
@WebServlet("/ResponseServlet")
public class ResponseServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public ResponseServlet() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException 
    {
        String a2 = "0";
        String a3 = "0";
        String n  = "0";

        response.setContentType("text/text");
        try (PrintWriter out1 = response.getWriter()) 
        {
            Connection conn = null;
            Statement stmt = null;
            ResultSet rs1 = null;
            int s = 0;

            try
            {
                Class.forName("com.mysql.jdbc.Driver");
                System.out.println("成功加載數據庫");
                conn = (Connection) DriverManager.getConnection("jdbc:mysql://localhost/mydata?" +
                                   "user=root&password=521314");
                stmt = (Statement) conn.createStatement();
                System.out.println("==");
                System.out.println("查詢最後一條記錄...");
                rs1 = stmt.executeQuery("SELECT * FROM t1 ORDER BY aid DESC LIMIT 1;");

                while(rs1.next())
                {
                    n = rs1.getString(2);
                    if (n.equals("1"))
                    {
                        a2 = "1";
                    }
                    else
                    {
                        a2 = "0";
                    }
                    n = rs1.getString(3);
                    if (n.equals("1"))
                    {
                        a3 = "1";
                    }
                    else
                    {
                        a3 = "0";
                    }

                }
            }
            catch (SQLException ex) 
            {
                System.out.println("Error in connection: " + ex.toString());
                System.out.println("SQLException: " + ex.getMessage());
                System.out.println("SQLState: " + ex.getSQLState());
                System.out.println("VendorError: " + ex.getErrorCode());
            } catch (ClassNotFoundException e) {
                // TODO 自動生成的 catch 塊
                e.printStackTrace();
            } 

            /* TODO output your page here. You may use following sample code. */
            //out1.println("<!DOCTYPE html>");
           // out1.println("<html>");
           // out1.println("<head>");
          //  out1.println("<title>Servlet myservlet2</title>");
           // out1.println("<meta charset=\"UTF-8\">");
           // out1.println("</head>");
           // out1.println("<body>");
            out1.println("A2=" + a2 + ",A3=" + a3 );
           // out1.println("</body>");
           // out1.println("</html>");

        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processRequest(request,response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // TODO Auto-generated method stub

        processRequest(request,response);

    }
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>

}

eclipse項目結構:
這裏寫圖片描述

MySQL

將MySQL已經圖形界面正確安裝好以後
打開workbench
這裏寫圖片描述

6服務器方面

6.1內網穿透的準備

6.1.1花生殼的準備

1打開花生殼進入內網穿透管理頁面:
這裏寫圖片描述
2.添加映射:
這裏寫圖片描述

6.1.2路由器的準備

1.進入路由器管理頁面(我用的是水星路由,其他的路由器設置過程類似)選擇高級設置–高級用戶
2添加虛擬服務器:
這裏寫圖片描述
這裏寫圖片描述
3.打開DMZ主機
這裏寫圖片描述
4.打開DDNS
這裏寫圖片描述

6.2.將web項目部署到Tomcat:

因爲eclipse默認是把web項目部署到名字空間下的文件夾裏,所以我們要設置eclipse將項目自動部署到Tomcat下。
Step1:
找到如圖所示的選項並執行。
這裏寫圖片描述

Step2:
找到如圖所示的選項並執行。
這裏寫圖片描述

Step3:
點擊open
這裏寫圖片描述

Step4:
依圖操作
這裏寫圖片描述

Step5:
退出保存重啓eclipse然後重新運行此項目,接着你去Tomcat的webapps文件夾下就可以找到你的項目了。
2.配置Tomcat
進入Tomcat安裝目錄的conf文件夾找到 server.xml
這裏推薦用 Notepad++打開。
找到

<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>

將端口號(port)8080改成80;接着在找到標籤,
在之前加上:

<Context path=""docBase="你的項目名稱"debug="0"reloadable="true"/>

關閉並保存。到這裏就大功告成了慶祝一下
後記:
這篇博文其實有很多細節都沒說,但是我想在一篇博文裏面塞那麼多東西只會顯得太臃腫雜亂,我就先把主要的部分寫了出來,在實際做的時候。作爲小白,比我剛開始學習kevinzhang樓主老師的帖子的時候,我就遇到了很多困難,比如,沒有用過eclipse做web項目的我,對如何創建一個項目,如何讓eclipse連接MySQL,如何使用JDBC來與數據庫交互。。。等等都是以一無所知,帖子裏也沒有講,我只能自學。我沒有用過花生殼,帖子裏也沒有詳細講如何使用。那些沒有講的東西都是需要靠自學才能瞭解的。然而那些讓我困擾的東西,我會另寫博客來說明,當然你也可以去自己百度。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章