注:該項目參考自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:ControlServlet和 ResponseServlet:
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來與數據庫交互。。。等等都是以一無所知,帖子裏也沒有講,我只能自學。我沒有用過花生殼,帖子裏也沒有詳細講如何使用。那些沒有講的東西都是需要靠自學才能瞭解的。然而那些讓我困擾的東西,我會另寫博客來說明,當然你也可以去自己百度。