고급 예제

다양한 도구들을 가지고 마음껏 응용해보세요.

아두이노에서 WiFi와 기상청의 RSS를 이용하여 날씨정보 읽어오기

2016-03-07 10:50:46

개요

 

코코아팹에 이 전에도 WiFi쉴드를 이용하여 날씨정보를 읽어오는 글이 있었습니다.

(링크 : http://kocoafab.cc/make/view/359)

 

아래 사진에 보이는 OpenWeatherMap사이트에서 API를 사용하여 날씨정보를 읽어왔습니다.

OpenweatherMap에서는 XML방식과 JSON방식 모두를 지원하여 JSON타입의 데이터를 파싱하여 읽어왔는데요.

 

 

 

 

하지만 국내에서도 이런 날씨와 관련된 정보를 제공해 주는 곳이 있습니다!

국내의 날씨정보를 수집하는 곳이라 하면 바로 기상청인데요. (http://www.kma.go.kr/) 국내에서 날씨 정보에 관한 모든 데이터를 수집하는 곳이니 만큼 여러 가지 정보를 기상청에서 찾아볼 수 있습니다.

 

<기상청에서는 국내의 날씨정보에 관한 모든것을 얻을 수 있다>

 

 

 

기상청의 인터넷 서비스에 관한 정보는 아래 링크나 홈 > 날씨 > 생활과 산업 > 서비스 > 인터넷 > 웹에서 확인이 가능합니다.

링크 : http://www.kma.go.kr/weather/lifenindustry/sevice_website.jsp

 

 

 

 

이 페이지에서 기상청의 RSS를 찾아볼 수 있습니다.

RSS란 rich site summary/really simple syndication/RDF site summary의 약자로

업데이트가 빈번한 웹 사이트의 정보를 쉽게 제공하기 위해서 만든 XML기반의 데이터 포맷입니다.

 

 

 

 

웹사이트 중에서 뉴스나 블로그의 정보는 수시로 업데이트가 되고 내용이 갱신되기도 하는데 예전에는 이런 정보를 직접 사이트에 접속하고 수시로 확인했다면

이제는 이런 데이터를 제공할때 RSS방식으로 제공하여 사용자는 RSS reader를 사용하여 쉽게 업데이트되는 정보를 한 페이지에서 모두 확인할 수 있습니다.

 

이번 글에서는 RSS데이터를 가지고 아두이노에서 파싱(Parsing)하여 시리얼모니터에 간단하게 정보를 띄워보도록 하겠습니다.

대부분의 코드는 이전 글(http://kocoafab.cc/make/view/359)에서 가져왔으니 이전글도 같이 참조하세요

 

 

 

필요한 부품 목록

 


 

NO 부품명 수량 상세설명
1 오렌지보드 1 아두이노UNO호환
2 WiFi쉴드 1  

 

부품명 오렌지보드 WiFi쉴드
부품사진

 

 

 

소프트웨어coding

#include "SPI.h"
#include "WiFi.h"

char ssid[] = "SSID";       //와이파이 SSID
char pass[] = "PASSWORD";   //와이파이 password 

//인스턴스 변수 초기화
WiFiServer server(80);
WiFiClient client;

IPAddress hostIp;
uint8_t ret;

int temp = 0;

String weather_str="";
String wt_temp="";
String wt_wfKor="";
String wt_wfEn="";
String wt_reh="";

void setup() {
	//각 변수에 정해진 공간 할당
	Serial.begin(115200);    
	
	delay(10);
	//WiFi연결 시도
	Serial.println("Connecting to WiFi....");  
	WiFi.begin(ssid, pass);  //WiFi가 패스워드를 사용한다면 매개변수에 password도 작성
	
	server.begin();
	Serial.println("Connect success!");
	Serial.println("Waiting for DHCP address");
	//DHCP주소를 기다린다
	while(WiFi.localIP() == INADDR_NONE) {
		Serial.print(".");
		delay(300);
	}
	
	Serial.println("\n");
	printWifiData();
	connectToServer();
}

void loop() {
	if (client.connected()) {
		while (client.available()) {
			//라인을 기준으로 문자열을 저장한다.
			String line = client.readStringUntil('\n');
			Serial.println(line);
			
			//시간
			int temp11= line.indexOf("</hour>");
			if(temp11>0) {
				String tmp_str="<hour>";
				String wt_hour = line.substring(line.indexOf(tmp_str)+tmp_str.length(),temp11);
				Serial.print("hour is "); 
				Serial.println(wt_hour);  
			}
			
			//온도
			int temp= line.indexOf("</temp>");
			if(temp>0) {
				String tmp_str="<temp>";
				String wt_temp = line.substring(line.indexOf(tmp_str)+tmp_str.length(),temp);
				Serial.print("temperature is "); 
				Serial.println(wt_temp);  
			}
			
			//날씨 정보
			int wfEn= line.indexOf("</wfEn>");
			if(wfEn>0) {
				String tmp_str="<wfEn>";
				String wt_twfEn = line.substring(line.indexOf(tmp_str)+tmp_str.length(),wfEn);
				Serial.print("weather is ");
				Serial.println(wt_twfEn);  
			}
			
			//습도
			int reh= line.indexOf("</reh>");
			if(reh>0) {
				String tmp_str="<reh>";
				String wt_reh = line.substring(line.indexOf(tmp_str)+tmp_str.length(),reh);
				Serial.print("Humidity is ");
				Serial.println(wt_reh);  
			}
		}   
	}
}

//서버와 연결
void connectToServer() {
	Serial.println("connecting to server...");
	String content = "";
	if (client.connect(hostIp, 80)) {
		Serial.println("Connected! Making HTTP request to www.kma.go.kr");
		//Serial.println("GET /data/2.5/weather?q="+location+"&mode=xml");
		client.println("GET /wid/queryDFSRSS.jsp?zone=1162058500 HTTP/1.1"); 
		//위에 지정된 주소와 연결한다.
		client.print("HOST: www.kma.go.kr\n");
		client.println("User-Agent: launchpad-wifi");
		client.println("Connection: close");
		
		client.println();
		Serial.println("Weather information for ");
	}
	//마지막으로 연결에 성공한 시간을 기록
}


void printHex(int num, int precision) {
	char tmp[16];
	char format[128];
	
	sprintf(format, "%%.%dX", precision);
	
	sprintf(tmp, format, num);
	Serial.print(tmp);
}

void printWifiData() {
	// Wifi쉴드의 IP주소를 출력
	Serial.println();
	Serial.println("IP Address Information:");  
	IPAddress ip = WiFi.localIP();
	Serial.print("IP Address: ");
	Serial.println(ip);
	
	//MAC address출력
	byte mac[6];  
	WiFi.macAddress(mac);
	Serial.print("MAC address: ");
	printHex(mac[5], 2);
	Serial.print(":");
	printHex(mac[4], 2);
	Serial.print(":");
	printHex(mac[3], 2);
	Serial.print(":");
	printHex(mac[2], 2);
	Serial.print(":");
	printHex(mac[1], 2);
	Serial.print(":");
	printHex(mac[0], 2);
	Serial.println();
	//서브넷 마스크 출력
	IPAddress subnet = WiFi.subnetMask();
	Serial.print("NetMask: ");
	Serial.println(subnet);
	
	//게이트웨이 주소 출력
	IPAddress gateway = WiFi.gatewayIP();
	Serial.print("Gateway: ");
	Serial.println(gateway);
	
	Serial.print("SSID: ");
	Serial.println(WiFi.SSID());
	
	ret = WiFi.hostByName("www.kma.go.kr", hostIp);
	
	Serial.print("ret: ");
	Serial.println(ret);
	
	Serial.print("Host IP: ");
	Serial.println(hostIp);
	Serial.println("");
}

int getInt(String input){
	int i = 2;
	
	while(input[i] != '"'){
		i++;
	}
	input = input.substring(2,i);
	char carray[20];
	//Serial.println(input);
	input.toCharArray(carray, sizeof(carray));
	//Serial.println(carray);
	temp = atoi(carray);
	//Serial.println(temp);
	return temp;
}

 

 

 

 

 

 

RSS인 만큼 시리얼 모니터에 출력되는 데이터는 아래 시리얼 모니터에 뜬 글자와 같이 XML형식으로 출력됩니다. 

아래 시리얼 모니터는 XML데이터를 그대로 받은 모습입니다.(중간에 깨져서 보이는 글자는 한국어입니다.)

 

 

 

 

여기서 뽑을 수 있는 기상 데이터 정보를 뽑아보면 아래와 같이 있습니다.

 

데이터 코드값 정보

 

코드 데이터 비고
<hour> 시간 24시간 표현
<day> 날짜 오늘 : 0, 내일 : 1, 모레 : 2
<temp> 온도  
<tmx> 최고 기온  
<tmn> 최저 기온  
<sky> 하늘 상태 맑음 : 1, 구름 조금 : 2, 구름 많음 : 3, 흐림 : 4
<pty> 강수형태 없음 : 0, 비 : 1, 비/눈 : 2, 눈 : 3
<pop> 강수확률 (%)
<ws> 풍속  
<wd> 풍향  
<reh> 습도 (%)
<r12> 12시간 강수량  
<s12> 12시간 신적설  
<r06> 6시간 강수량  
<s06> 6시간 신적설  

 

 

 

URL을 보면 http://www.kma.go.kr/wid/queryDFSRSS.jsp?zone=1165053000 와 같은 형식으로 되어있는데 뒤에 보면 10자리의 지역별 코드가 존재합니다.

지역별 코드는 크게 시/도 -> 시/군/구 -> 읍/면/동 으로 볼 수 있습니다.

위의 URL을 예로 들면 앞의 두자리 11은 시/도를 표현하고, 그 다음 세자리인 650은 시/군/구 나머지 5자리는 읍/면/동을 표현합니다.

지역에 맞춰서 지역코드를 입력해주시면 지역별 날씨 정보를 읽어올 수 있습니다.

 

참고로 아래 URL에서 지역별 코드를 확인할 수 있습니다. 

※ 아래의 지역코드에서 한글이 깨져서 보이실 경우 텍스트 인코딩을 UTF-08 로 체크하면 볼 수 있습니다.

 

시/도 지역 코드 : http://www.kma.go.kr/DFSROOT/POINT/DATA/top.json.txt

 

시/군/구 : http://www.kma.go.kr/DFSROOT/POINT/DATA/mdl.11.json.txt

- 위의 URL에서 빨간글씨로 표현된 곳은 시/도 코드 입력

 

읍/면/동 : http://www.kma.go.kr/DFSROOT/POINT/DATA/leaf.11545.json.txt

- 위의 URL에서 빨간글씨로 표현된 곳은 시/도와 시/군/구 코드 입력

 

 

 

※ 그래도 위의 방법이 귀찮으시다면 기상청의 홈페이지를 이용

http://www.kma.go.kr/weather/lifenindustry/sevice_rss.jsp

 

아래 사진에서 빨간색 사각형 안에 지역을 입력하고 RSS를 누르면 URL이 나오는데 뒤에 지역코드만 가져오시면 됩니다.

 

 

 

 

코드에서는 readStringUntil로 각 라인마다 String타입으로 데이터를 읽어옵니다.

readStringUntil은 ()안에 있는 문자가 올때까지 문자를 읽어서 String변수에 저장하게 됩니다.

위 코드에서는 라인피드 문자가 올때까지 문자를 읽기 때문에 각 라인마다 String변수에 저장합니다.

 

String line = client.readStringUntil('\n');

 

 

 

아래 코드를 통해 XML에서 원하는 데이터값을 파싱하는데 indexOf()함수로 라인에서 문자가 있는지 없는지 파악합니다.

indexOf()함수는 검색하는 위치에서 검색하고자 하는 문자가 있는지 파악하고 있을 경우 위치의 값을 int값으로 반환합니다.

 

간단히 아래의 코드로 예를 들면 <temp>부터 </temp>가 오기전까지의 그 사이의 값을 substring으로 읽어옵니다.

  

      int temp= line.indexOf("</temp>");
      if(temp>0)
      {
        String tmp_str="<temp>";
        String wt_temp = line.substring(line.indexOf(tmp_str)+tmp_str.length(),temp);
        Serial.print("temperature is "); 
        Serial.println(wt_temp);  
      }

 

 

 

위의 코드를 실행시키면 아래와 같이 원하는 데이터를 파싱하여 읽어올 수 있습니다.

위 코드에서는 온도와 기상정보, 습도를 읽어왔지만 원하는 데이터를 파싱부분만 추가한다면 얼마든지 뽑아서 읽어올 수 있습니다.

 

 

kocoafabeditor

항상 진취적이고, 새로운 것을 추구하는 코코아팹 에디터입니다!

Arduino, 아두이노, WiFi, 기상청, 날씨, weather

장세현 2016-03-15 19:25:57

감사합니다.

강상호 2016-09-12 14:14:35

잘보았습니다. 감사합니다.

양수진 2016-11-07 15:34:03

다음날의 날씨를 가져오는 방법도 있을까요? 현재 날씨 외에는 가져올수가 없는건가요!?

수박쨈 2016-11-07 15:41:39

위 사진을 보면 아시겠지만 3일치 날짜를 3시간 간격으로 한 번에 받아오기 때문에 다음날 날씨를 알 수 있습니다.

정해민 2016-11-16 17:12:59

Connecting to WiFi....
Connect success!
Waiting for DHCP address
똑같이 코딩하였는데 이런식으로 " ..... "계속 뜨면서 진행이 되지않습니다. 어떤문제일까요 ㅠㅠ