-
웹 페이지에서 아두이노로 LED On/Off 제어하기Arduino/Web Socket 2021. 1. 5. 21:32
우선 아래의 내용을 보기에 앞서 아래의 내용에서 Web Socket에 대해 알아보고 오도록 하자.
designatedroom87.tistory.com/347?category=909022
Dynamic Web Project로 프로젝트를 하나 생성하자.
이름은 WebSocketLED 라고 하자.
다이나믹 웹 프로젝트를 만드는 순서와 서버의 설정 등에 대한 정보는 아래에서 익히고 오도록 하자.
designatedroom87.tistory.com/321?category=903927
시리얼 통신을 위해서 RXTXcomm.jar파일과 rxtxSerial.dll파일을 추가하고 설정까지 해야 한다.
아래에서 시리얼 통신의 기본 설정에 대해서 하고 오도록 하자.
designatedroom87.tistory.com/315?category=903927
그리고 기존의 앞에서한 내용을 그대로 들고 올 것이다.
src폴더에 serial패키지를 하나 생성한다.
Main.java, Serial.java, SerialRead.java, SerialWrite.java, DataProc.java 파일을 그대로 들고온다.
모든 소스 파일은 맨 아래에 있다.
Main.java에서는 포트번호를 반드시 확인해야 한다. 컴퓨터마다 다르다.
Main.java
더보기package serial; public class Main { public static void main(String[] args) { try { (new Serial()).connect("COM6"); } catch(Exception e) { e.printStackTrace(); } } }
SerialWrite.java
더보기package serial; import java.io.IOException; import java.io.OutputStream; public class SerialWrite implements Runnable { OutputStream out; public SerialWrite(OutputStream out) {this.out = out;} @Override public void run() { int c = 0; try { while ((c = System.in.read()) > -1) { out.write(c); } } catch (IOException e) {e.printStackTrace();} } }
DataProc.java
더보기package serial; public class DataProc { String recvData; public DataProc(String recvData) { this.recvData = recvData; Print(); } public void Print() { System.out.println("DataProc : "+recvData); } }
SerialRead.java
더보기package serial; import java.io.IOException; import java.io.InputStream; // 값을 읽는 클래스로, 이는 Thread로 구현해야 한다. public class SerialRead implements Runnable { InputStream in; public SerialRead(InputStream in){this.in = in;} @Override public void run() { byte[] buffer = new byte[1024]; int len = -1; try { // buffer에 저장하고나서, 그 길이를 반환한다. while ((len = this.in.read(buffer)) > -1) { // System.out.println(new String(buffer,0,len)); // new DataProc(new String(buffer,0,len)); String s = new String(buffer,0,len); if (len != 0) new DataProc(s); } } catch (IOException e) {e.printStackTrace();} } }
Serial.java
더보기package serial; import java.io.InputStream; import java.io.OutputStream; import gnu.io.CommPort; import gnu.io.CommPortIdentifier; import gnu.io.SerialPort; public class Serial { void connect(String port) { CommPort commPort = null; SerialPort serialPort = null; try { CommPortIdentifier com = CommPortIdentifier.getPortIdentifier(port); // com포트를 확인하는 작업 if (com.isCurrentlyOwned()) System.out.println("Error : "+port +"포트를 사용중입니다."); // 포트가 열려있으면 else { commPort = com.open(this.getClass().getName(),1000); // 획득한 포트를 객체가 사용할 수 있는지 여부 확인 if (commPort instanceof SerialPort) // commPort가 SerialPort로 사용할 수 있는지 확인 { serialPort = (SerialPort)commPort; // 정상적으로 포트를 사용할 수 있을 경우 // 포트에 필요한 정보를 입력해 준다. serialPort.setSerialPortParams( 9600, // 바운드레이트 SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); // 오류제어 비트 } System.out.println("comport성공"); InputStream in = serialPort.getInputStream(); OutputStream out = serialPort.getOutputStream(); (new Thread(new SerialRead(in))).start(); new Thread(new SerialWrite(out)).start(); (new Thread(new SerialWebsocket(out))).start(); } } // end try catch(Exception e) {} } }
SerialWebsocket.java
더보기package serial; import java.io.OutputStream; import java.net.URI; import java.net.http.HttpClient; import java.net.http.WebSocket; import java.util.concurrent.CountDownLatch; public class SerialWebsocket implements Runnable { OutputStream out; // Constructor public SerialWebsocket(OutputStream out) {this.out = out;} @Override public void run() { try { CountDownLatch latch = new CountDownLatch(10); // 데이터를 10번만 받겠다는 의미 URI uri = URI.create("ws://localhost:9090/websocket"); WebsocketClientArduino listener = new WebsocketClientArduino(latch, out); WebSocket ws = HttpClient.newHttpClient().newWebSocketBuilder().buildAsync( uri, listener).join(); ws.sendText("java app sendmessage", true); latch.await(); }catch(Exception e) { e.printStackTrace(); } } }
그리고, src폴더에 websocket패키지를 하나 만든다.
이 패키지에 아래의 4개의 파일들을 만들 것이다.
webcontroller.java를 하나 만든다.
webcontroller.java
더보기package websocket; import java.io.IOException; import javax.servlet.RequestDispatcher; 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 javax.servlet.http.HttpSession; @WebServlet("/websocketcomm") public class webcontroller extends HttpServlet { private static final long serialVersionUID = 1L; protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { HttpSession session = request.getSession(); //페이지를 전송하기 전에 url을 분석하고 비교해서 실행 String url = request.getRequestURI(); //System.out.println("url : "+url); String contextPath = request.getContextPath(); //System.out.println("contextpath : "+contextPath); String path = url.substring(contextPath.length()); //System.out.println("path : "+path); //마지막 '/'를 기준으로 값 추출 String lastPath = url.substring(url.lastIndexOf('/')+1); System.out.println("subPath : "+ lastPath); //최종 주소 String command = lastPath; if(command.equals("led")) { RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/arduinoled.jsp"); dispatcher.forward(request, response); } else { RequestDispatcher dispatcher = request.getRequestDispatcher("/WEB-INF/arduinoled.jsp"); dispatcher.forward(request, response); } } }
WSocket.java파일을 하나 만든다.
WSocket.java
더보기package websocket; import java.util.Collections; import java.util.Set; import javax.websocket.OnClose; import javax.websocket.OnError; import javax.websocket.OnMessage; import javax.websocket.OnOpen; import javax.websocket.RemoteEndpoint.Basic; import javax.websocket.Session; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/websocket") public class WSocket { private static final Set<Session> sessions = Collections.synchronizedSet( new java.util.HashSet<Session>() ); /* // onopen 이벤트가 호출 되면 실행되는 함수 @OnOpen public void handleOpen() { System.out.println("클라이언트가 접속했습니다."); } */ // onopen 이벤트가 호출 되면 실행되는 함수 @OnOpen public void handleOpen(Session session) { System.out.println("클라이언트가 접속했습니다."); System.out.println("session id : " +session.getId()); sessions.add(session); } /* // onclose 이벤트가 호출 되면 실행되는 함수 @OnClose public void handleClose() { System.out.println("클라이언트가 연결을 해제했습니다."); } */ // onclose 이벤트가 호출 되면 실행되는 함수 @OnClose public void handleClose(Session session) { System.out.println(session.getId() + "클라이언트가 연결을 해제했습니다."); // 세션을 닫는다. sessions.remove(session); } // onerror 이벤트가 호출 되면 실행되는 함수 @OnError public void handleError(Throwable t) { t.printStackTrace(); } /* // onmessage 이벤트가 호출 되면 실행되는 함수 @OnMessage public String handleMessage(String message) { // 서버가 받는다. System.out.println("클라이언트가 보내온 메시지 : "); System.out.println(message); return "메시지 수신 완료"; } */ // onmessage 이벤트가 호출 되면 실행되는 함수 @OnMessage public void handleMessage(String message, Session session) { // 서버가 받는다. System.out.println("클라이언트가 보내온 메시지 : "); System.out.println(message); this.sendAll(session, message); try { final Basic basic = session.getBasicRemote(); basic.sendText(message); }catch(Exception e) {} } public void sendAll(Session session, String message) { System.out.println(session.getId() + ":" +message); try { int i = 0; // 웹 소켓에 연결되어 있는 모든 아이디를 찾는다. for (Session s : WSocket.sessions) { System.out.println(++i); if (!s.getId().equals(session.getId())) { s.getBasicRemote().sendText(message); } } }catch(Exception e) {e.printStackTrace();} } }
WebsocketClient.java
더보기package websocket; import java.net.http.WebSocket; import java.net.http.WebSocket.Listener; import java.util.concurrent.CompletionStage; import java.util.concurrent.CountDownLatch; // 자바에서 지원하는 기본적인 소켓을 만든 것이다. // WebSocket.Listener를 통해, 웹 소켓에 접속할 것이다. public class WebsocketClient implements WebSocket.Listener { // 웹 소켓에서 전송되는 데이터 수를 정하는 변수 // 만약, 3번만 데이터를 수신하고 싶으면 3으로 설정 // 웹 소켓이 닫히게 된다. onClose함수가 자동으로 실행된다. private final CountDownLatch latch; // 몇번을 받을 것인가? // 사용할 횟수만큼 매개변수로 전달하면 된다. public WebsocketClient( CountDownLatch latch) { this.latch = latch; } @Override // 서버에 접속했을 때, 호출된다. public void onOpen(WebSocket webSocket) { System.out.println("arduino websocket open"); Listener.super.onOpen(webSocket); } @Override public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) { System.out.println("arduino websocket close"); return Listener.super.onClose(webSocket, statusCode, reason); } @Override public void onError(WebSocket webSocket, Throwable error) { System.out.println("arduino websocket error"); Listener.super.onError(webSocket, error); } @Override // 메시지(텍스트)가 도착했을 때, 호출되는 함수 public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) { System.out.println("websocketclient recv message : " +data); this.latch.countDown(); return Listener.super.onText(webSocket, data, last); } }
SocketMain.java
더보기package websocket; import java.net.URI; import java.net.http.HttpClient; import java.net.http.WebSocket; import java.util.concurrent.CountDownLatch; public class SocketMain { public static void main(String[] args) { try { CountDownLatch latch = new CountDownLatch(10); // 데이터를 10번만 받겠다는 의미 URI uri = URI.create("ws://localhost:9090/websocket"); WebsocketClient listener = new WebsocketClient(latch); WebSocket ws = HttpClient.newHttpClient().newWebSocketBuilder().buildAsync( uri, listener).join(); ws.sendText("java app sendmessage", true); latch.await(); }catch(Exception e) { e.printStackTrace(); } } }
우선 WEB-INF폴더에 jsp파일을 하나 만들자.
파일의 이름은 arduinoled.jsp라고 한다.
arduinoled.jsp파일에는 LED를 제어할 ON/OFF버튼만 만들어 두었다.
arduinoled.jsp
더보기<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> </head> <body> <button onclick="ws.send('1')">LED ON</button><p> <button onclick="ws.send('0')">LED OFF</button><p> <input type="range" id="vol" name="vol" min="0" max="180" onchange="ws.send(this.value)"> <script> var ws = new WebSocket("ws://localhost:9090/websocket"); ws.onopen = function() {console.log('open')} ws.onmessage = function(event) { console.log(event.data);} ws.onopen = function(event) {console.log('close')} ws.onopen = function(event) {console.log('error')} </script> </body> </html>
WebsocketClientArduino.java
더보기package serial; import java.io.IOException; import java.io.OutputStream; import java.net.http.WebSocket; import java.net.http.WebSocket.Listener; import java.util.concurrent.CompletionStage; import java.util.concurrent.CountDownLatch; // 자바에서 지원하는 기본적인 소켓을 만든 것이다. // WebSocket.Listener를 통해, 웹 소켓에 접속할 것이다. public class WebsocketClientArduino implements WebSocket.Listener { // 웹 소켓에서 전송되는 데이터 수를 정하는 변수 // 만약, 3번만 데이터를 수신하고 싶으면 3으로 설정 // 웹 소켓이 닫히게 된다. onClose함수가 자동으로 실행된다. private final CountDownLatch latch; // 몇번을 받을 것인가? private OutputStream out; // 사용할 횟수만큼 매개변수로 전달하면 된다. public WebsocketClientArduino( CountDownLatch latch, OutputStream out) { this.latch = latch; this.out = out; } @Override // 서버에 접속했을 때, 호출된다. public void onOpen(WebSocket webSocket) { System.out.println("arduino websocket open"); Listener.super.onOpen(webSocket); } @Override public CompletionStage<?> onClose(WebSocket webSocket, int statusCode, String reason) { System.out.println("arduino websocket close"); return Listener.super.onClose(webSocket, statusCode, reason); } @Override public void onError(WebSocket webSocket, Throwable error) { System.out.println("arduino websocket error"); Listener.super.onError(webSocket, error); } @Override // 메시지(텍스트)가 도착했을 때, 호출되는 함수 public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) { System.out.println("arduino recv message : " +data); this.latch.countDown(); try {this.out.write(data.toString().getBytes());} catch (IOException e) {e.printStackTrace();} return Listener.super.onText(webSocket, data, last); } }
아두이노와 LED를 연결한다.
8번핀에 연결한다. 그리고 아래의 소스 파일을 아두이노에 업로드 한다.
아두이노 소스파일
더보기void setup() { // put your setup code here, to run once: Serial.begin(9600); pinMode(8, OUTPUT); digitalWrite(8, LOW); } void loop() { // put your main code here, to run repeatedly: if ( Serial.available() ) { byte ledState = Serial.read(); if ( ledState == '1' ) digitalWrite(8, HIGH); else if ( ledState == '0' ) digitalWrite(8, LOW); } }
서버를 먼저 실행하고, 웹 페이지에 접속해서 http://localhost:9090/websocketcomm로 접속한다.
그리고 serial패키지의 Main.java를 실행한다.
그리고 나서 LED의 On/Off 버튼을 클릭해보자.
소스 파일
위의 파일을 내려받아서 이클립스에서 우클릭하고 import를 하면 된다.
그리고 나서 실행하면 된다.
다만 실행하다가 아래와 같은 에러가 발생하면 WEB-INF/lib폴더의 RXTXcomm.jar 파일과 rxtxSerial.dll 파일을 지우고
다시 설정을 해야 한다.
'Arduino > Web Socket' 카테고리의 다른 글
한 컴퓨터에서 서보 모터와 7Segment 제어하기 (0) 2021.01.14 한 컴퓨터로 2대의 아두이노 제어하기(서보모터 동시에 동작) (0) 2021.01.12 RFID의 값에 따라 LED의 On/Off 제어하기 (0) 2021.01.09