22.02.25 웹에서 Json - 아두이노 데이터 주고받기

ggg4155·2022년 2월 25일
0

Json - 아두이노 데이터 주고받기

-데이터를 주고 받기 위해 일정 포맷이 필요 - 비교적 쉬운 json사용

  • 타기종간 데이터 주고 받을 때 , 서버간 데이터 주고 받을 때 사용되는 포맷들
    -CSV
    name,nanana,age,21
    -xml
    < name>nanana< /name>
    < age>21< /age>
    -json
    {"name":"nanana", "age":21} key:value
  • 아두이노 json 사용하기
    스케치-라이브러리포함하기-zip라이브러리 추가 -ArduinoJson로 자동완성

  • html문서에서 서블릿으로 값 전송 -> 값을 받은 서블릿파일은 json데이터 형식으로 아두이노에 데이터 전송

  1. index.html on/off 체크 radio만들기
  2. Exam01.java 서블릿 만들기
  3. 아두이노 DynamicJsonBuffer jsonBuffer 라는 유동적 메모리구조 만들어주기
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<form action="Exam01">
		<table border="1px black">
			<tr>
				<td></td>
				<td>ON</td>
				<td>OFF</td>
			</tr>
			<tr>
				<td>LED</td>
				<td><input type="radio" name="led" value="1"></td>
				<td><input type="radio" name="led" value="0" checked="checked"></td>
			</tr>
		</table>
		<input type="submit" value="제어">
		<!-- checked : 기본값 -->
	</form>
</body>
</html>
Insert title here
ON OFF
LED
package test;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/Exam01")
public class Exam01 extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter(); //출력스트림 객체생성
		
		String led = request.getParameter("led"); 
        	//html로 받아온 데이터led
		System.out.println(led);
			//콘솔창에 출력
		//JSON data 아두이노로 전송
		// \:escape code
		if(led.equals("1")) {
			out.print("{\"LED\":\"1\"}");
		}else if(led.equals("0")) {
			out.print("{\"LED\":\"0\"}");
		}
	}
}

#include <ArduinoJson.h>
#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "id";	//wifi-id
const char* password =  "pw";	//wifi-pw

String result = "";

int ledPin = 18;
void setup() {
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("Connecting to WiFi..");
  }
  Serial.println("Connected to the WiFi network");
}

void loop() {
  if ((WiFi.status() == WL_CONNECTED)) { //Check the current connection status
    HTTPClient http;
    http.begin("http://ip4주소:8090/IoT/Exam01"); //Specify the URL //localhost가 아닌 ipv4 주소를 입력해야 아두이노에서 접근
    int httpCode = http.GET();                                        //Make the request

    if (httpCode > 0) { //Check for the returning code

      Serial.println(httpCode);	
      result = http.getString();
      Serial.println(result);
      //위주소에서 가져온 값을 저장하고 시리얼모니터에 출력
      
      DynamicJsonBuffer jsonBuffer; 
    //json데이터를 유동적으로 다룰  수 있는 메모리 공간
      JsonObject& root = jsonBuffer.parseObject(result);
      String LED = root["LED"];   //현재 상태 
      if(LED == "1"){
        digitalWrite(ledPin,1);
      }else if(LED == "0"){
        digitalWrite(ledPin,0);
      }
    }
    else {
      Serial.println("Error on HTTP request");
    }
    http.end(); //Free the resources
  }
  delay(1000);
}

index.html에서 전송받은 값을 Json데이터형식으로 변환해 아두이노로 전송하게되면
서블릿 콘솔창에는 led is null 이라는 오류와 html로 넘어온 값(1 or 0)이 출력되고, 아두이노로부터 계속해서 요청이 오기 때문에 null도 함께 출력되는 것을 볼 수 있다.

아두이노 - 서버 데이터 통신시 오류가 나는 이유 >> 메모리 구조 때문

잠시 java의 메모리 구조를 살펴보자

Java의 메모리 영역

  • heap 영역 : 선언된 변수, 배열, 레퍼런스변수(new키워드) 등 => new키워드 붙이면 메모리에 직접적으로 생성된다. 잘안쓰이면 Garbage Collection에의해 불필요한 메모리 자동으로 삭제됨

  • stack영역 : static이나 static이 붙은 변수, main => main에서 static없는 메소드는 호출안됨
    static이 없는 메소드 호출시 클래스명.메소드(); 또는 new 키워드로 변수 없이 클래스명.메소드();

Exam메모리와 Exam호출 자바 클래스를 만들어 살펴보았다. => 다이나믹 웹 프로젝트에서 잠시 자바 환경으로 바꿔 작업해줌 (템플릿이 다름) open perspective 체크해준다

import java.util.ArrayList;

public class Exam메모리 {
	
	//클래스내 필드선언
	public static int num = 5;
	public int num2 = 10;

	public static void main(String[] args) {

		Exam메모리 ex1 = new Exam메모리();
		
		ex1.addNumber(5,3);
		new Exam메모리().addNumber(5, 3); 
        //static이 없는 메소드 호출시 클래스명.메소드(); 또는 new 키워드로 변수 없이 클래스명.메소드();  할 수 있다!
		
		printLunch();
		//static 메소드 특징 기울임꼴, 다른클래스에서 호출가능
		
		ArrayList<String> list = new ArrayList<>();
		list.add("문자열");
		ArrayList<int[]> list2 = new ArrayList<int[]>();
		int[] ages = new int[27];
		list2.add(ages);
		list2.add(new int[] {1,3,4});
		
		
	}
	public void addNumber(int num1, int num2) {
		System.out.println(num1+num2); 
	}
	
	public static void printLunch() {
		System.out.println("뭐먹지");
	}

}

public class Exam호출 {

	public static void main(String[] args) {
		
		Exam메모리.printLunch();
		//다른클래스에서 호출할때, static은 어디서나 호출가능하지만, 어디에있는지 클래스명 명시하기
		new Exam메모리().addNumber(5,3);
		//static이아니라면 해당클래스를 new라는 키워드로 호출해서 heap영역에 올려서 사용하기
		
		System.out.println(Exam메모리.num); //static- stack영역
		System.out.println(new Exam메모리().num2); //new키워드
		
		Exam메모리.num = 1000;
		new Exam메모리().num2 = 1000;
		
		//static변수는 stack영역에 올라가있음
		//어느클래스에서 사용할수있어서 다르클래스에서 값 수정시 모든클래스에 반영됨
		
		System.out.println(Exam메모리.num);
		System.out.println(new Exam메모리().num2);
        //heap영역의 변수는 변경 값 올라가지만 다음코드진행되면서 사라짐 다시 호출했을때 들어있던 처음 값이 10이므로 바로 사용되지 않아 변경값 사라져 처음 값
	}

}

문제 해결:

html에서 값을 가져올 수는 있었지만 아두이노에서 요청할 때 led라는 key값이 없어서 오류가 남 -> 값을 static으로 변경해서 항상 존재하는 값으로 만들어줌
변수에 static 키워드를 붙이고, static 키워드에 led 정보를 넣어서 어느클래스에서든 그 정보를 가져올 수 있게함 ! 다른 클래스에서도 정보를 유지하게함

  1. 새로운 서블릿 클래스 파일 만들어줌 doGet, doPost, Constructors 해제 Sevice체크
  2. 클래스 바로 밑 계층에 전역 변수 선언해주기
    public static String led = "0";
  3. index.html에서 Exam01이 아닌 send로 데이터 전송받도록 하기
    led = request.getParrameter("led"); (위에선언한 led에 담아줌)
  4. controller 역할이기 때문에 페이지가 바로 보이면 안됨, 값만 수정하고 바로 다시 index페이지로 보내줘야됨
    response.sendRidirect("index.html");
  5. index.html에서 폼태그에서 보내는 주소를 send로 바꿔줌
  6. Exam01에서는 parameter 수집할 필요가 없음
    클래스명.가져올필드
    String led = send.led;
    send.led는 static-stack영역 변수, String led는 지역변수
package test;

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


@WebServlet("/Send")
public class Send extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public static String led = "0"; //static 필드 선언부
	
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

		led = request.getParameter("led"); //index.html led 키값을 받아옴
		response.sendRedirect("index.html"); //값만 받아서 바로 페이지로 보내줌
		
	}

}
package test;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/Exam01")
public class Exam01 extends HttpServlet {
	private static final long serialVersionUID = 1L;

	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		response.setContentType("text/html; charset=UTF-8");
		PrintWriter out = response.getWriter();
		
		String led = Send.led; 	//send클래스의 led를 새로운 지역변수 led에 담아줌
		//send.led는 static-stack영역, String led는 지역변수
		
		//JSON data를 출력
		// \:escape code
		if(led.equals("1")) {
			out.print("{\"LED\":\"1\"}");
		}else if(led.equals("0")) {
			out.print("{\"LED\":\"0\"}");
		}
	}
}

<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<form action="Send">			//send로 보냄
		<table border="1px black">
			<tr>
				<td></td>
				<td>ON</td>
				<td>OFF</td>
			</tr>
			<tr>
				<td>LED</td>
				<td><input type="radio" name="led" value="1"></td>
				<td><input type="radio" name="led" value="0" checked="checked"></td>
			</tr>
		</table>
		<input type="submit" value="제어">

		<!-- checked : 기본값 -->

	</form>
</body>
</html>
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h>


const char* ssid = "??";
const char* password =  "??";

String result = "";
int ledPin=18;

void setup() {
  pinMode(18,OUTPUT);
  Serial.begin(115200);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.println("Connecting to WiFi..");
  }

  Serial.println("Connected to the WiFi network");

}

void loop() {

  if ((WiFi.status() == WL_CONNECTED)) { //Check the current connection status

    HTTPClient http;

    http.begin("http://192.168.137.1:8090/IoT/Exam01"); //Specify the URL
    int httpCode = http.GET();                                        //Make the request

    if (httpCode > 0) { //Check for the returning code

      Serial.println(httpCode);
      result = http.getString();
      Serial.println(result);
	//위주소에서 가져온 값을 저장하고 시리얼모니터에 출력
      
      DynamicJsonBuffer jsonBuffer; 
    //json데이터를 유동적으로 다룰  수 있는 메모리 공간
      JsonObject& root = jsonBuffer.parseObject(result);
      String LED = root["LED"]; 
      if(LED=="1"){
        digitalWrite(ledPin,1);
      }else if(LED=="0"){
        digitalWrite(ledPin,0);
      }
    }
    else {
      Serial.println("Error on HTTP request");
    }

    http.end(); //Free the resources
  }

  delay(1000);
}

0개의 댓글