WiFi를 통한 아두이노 활용 (19) : 아이폰 연동 #3

2017. 8. 30. 08:25

Arduino/Wireless

Arduino로 iphone에 데이터 전송하기 #3

이번 글에선 Label, PickerView 객체를 이용하여 프로그램 나머지 부분을 완성하겠습니다.

Label object 추가

파싱된 데이터를 간단하게 아이폰 화면에 표시하기 위해 Label object를 하나 사용하겠습니다.

우선 Label 하나 추가합니다. Button을 추가할 때와 마찬가지로 Xcode 화면 오른쪽 하단 Object Library에서 끌어다 놓고 크기를 조절합니다. 또 오른쪽 상단 Attributes Inspector 화면에서 원하는 속성으로 설정합니다. 디폴트로 들어있는 "Label" 문자열을 삭제하고 Lines도 10 정도로 높여서 여러 줄을 출력할 수 있도록 합니다.

이렇게 추가한 Label은 역시 아무 일도 하지 않습니다. 그냥 화면 레이아웃만 수정했을 뿐 관련된 코딩이 아직 없기 때문입니다. 프로그램에서 이 Label을 사용하기 위해서는 두 가지가 더 필요합니다. 적당한 코드가 있어야 하고 또 그 코드와 Label 객체의 Connection이 필요합니다. Request Button을 추가할 때와 마찬가지인데, 버튼은 특정 동작과 연결하기 위해 @IBAction 타입으로 선언했고, Label은 텍스트를 입력 받을 통로가 필요하므로 @IBOutlet type으로 선언합니다. 역시 코딩창으로 드래그해서 추가하면 편합니다.

Button 때와 마찬가지로 Interface Builder(main.storyboard) 화면과 코드(ViewController.swift) 화면을 나란히 열어 놓습니다. Main.storyboard가 선택된 상태에서 Project Navigator에서 ViewController.swift를 option key를 누른 채 클릭하면 쉽게 배치할 수 있습니다.

@IBAction은 함수이기에 클래스 내의 아래쪽에 코딩했고, @IBOutlet은 변수와 같기에 클래스 상단에 끌어다 놓습니다.

Label을 코딩창에 끌어다 놓으면 왼쪽 그림과 같이 팝업 메뉴가 나타나고 적당한 이름을 주고 Connect 합니다. 그러면 해당 코드가 자동으로 입력되고 오른쪽 그림과 같이 Connections Inspector 화면에서 연결 내용을 확인할 수 있습니다.

//
//  ViewController.swift
//  arduinoWeather
//
//  Created by turtle on 2017. 8. 25..
//  Copyright © 2017년 turtleShell. All rights reserved.
//
import UIKit
class ViewController: UIViewController, XMLParserDelegate {
    var parser = XMLParser()
    @IBOutlet var label: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

코드창에서도 위와 같이 @IBOutlet 변수 label이 선언되었습니다. 이제 프로그램 상에서 label 변수를 통해 Label object에 텍스트를 출력할 수 있습니다.

XML 데이터에 대한 처리는 start tag, contents, end tag 중, end tag가 나오는 시점에서 하겠습니다. start tag가 나오는 시점엔 아직 contents가 오질 않았기 때문이고, 또 start tag와 end tag가 짝을 이루는지 확인 후에 처리하는 게 안전할 듯 해서 입니다.

파싱된 XML 데이터를 처리하는 3개의 함수는 각각 elementName, string에 그 데이터를 가지고 있습니다. 하지만 이 변수들은 지역 변수이기 때문에 해당 함수내에서만 사용할 수 있습니다. 따라서, 입력 받은 데이터를 다른 함수들에서도 사용할 수 있도록 전역 변수에 담아서 사용하도록 하겠습니다.

class ViewController: UIViewController, XMLParserDelegate {
    var parser = XMLParser()
    var currentStart = ""
    var currentContent = ""
    @IBOutlet var label: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
    }

위와 같이 start tag와 contents를 위한 전역 변수를 선언하고 공백으로 초기화하였습니다. 모든 처리는 end tag가 나오는 시점에 parser( didEndElements )함수 내에서 하기 때문에 end tag를 위한 변수는 필요 하지 않습니다.

func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
        currentStart = elementName
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
        currentContent = string
}

start tag, contents를 각각 저장하는 부분입니다. 그 외에 다른 처리는 하지 않습니다. 만약 시작 태그에 어트리뷰트가 존재한다면 그에 대한 처리를 여기서 해야 합니다.

func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
    if elementName != "weather" && elementName == currentStart {
        if elementName == "country" {
            label.text = label.text! + "Country : " + currentContent
        }
    }
}

parser( didEndElement ) 함수이기 때문에 elementName 인수에는 end tag가 들어 있습니다. 아두이노 웹서버에서 전송해주는 XML 데이터는 <weather></weather> 태그로 묶여 있고 이 태그에 대한 처리는 필요 없기 때문에, weather가 아닐 경우에만 처리하도록 IF문을 구성하였습니다. 또, 시작 태그와 종료 태그는 짝을 이루어야 하기 때문에 두 값이 동일할 경우에만 처리하는 조건도 같이 넣었습니다.

위 코드는 우선 테스트로 country 태그에 대해서만 처리합니다. 태그 이름이 "country"라면 label.text를 통해 Label object에 currentContent를 추가합니다.

여기까지 실행하고 나서의 콘솔창 내용과 시뮬레이터 모습입니다.

PickerView로 원하는 도시 선택하기

현재 아두이노와 아이폰 모두 서울에 대한 날씨 정보만 처리하도록 되어 있습니다. 이제 원하는 도시를 선택해서 요청하도록 하겠습니다. 우선 두 개의 배열이 필요합니다.

class ViewController: UIViewController, XMLParserDelegate {
    var parser = XMLParser()
    var currentStart = ""
    var currentContent = ""
    let cityID = ["1835847", "1838519", "1835327", "1843561", "1841808", "1835224", "1833742"]
    let cityName = ["서울특별시", "부산광역시", "대구광역시", "인천광역시", "광주광역시", "대전광역시", "울산광역시"]
    var currentCityID = "1835847"

openweathermap API에서 사용하는 도시 ID를 위한 배열 하나와 도시 이름을 위한 배열을 선언하였습니다. 그리고 현재의 도시 ID를 저장하기 위해 currentCityID 변수를 선언하고 서울의 도시 ID로 초기화하였습니다.

func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        if elementName != "weather" && elementName == currentStart {
            if elementName == "cityid" {
                if let index = cityID.index(of: currentContent) {
                    currentCityID = cityID[index]
                    label.text = label.text! + cityName[index]
                } else {
                    currentCityID = cityID[0]
                    label.text = label.text! + "Unknown City"
                }
            } else if elementName == "country" {
                label.text = label.text! + "Country : " + currentContent
            }
            label.text = label.text! + "\n"
        }
    }

country 태그에 대한 처리 위쪽에 cityid에 대한 처리를 추가하였습니다. 이 부분은 아두이노 쪽에서도 수정이 필요합니다.

태그 이름이 cityid이면 우선 전송 받은 city 아이디가 cityID 배열에 있는지 확인하는 작업이 필요합니다. 이를 위해 currentContent에 들어 있는 전송 받은 city 아이디를 배열에서 찾아서 그 위치값을 index 상수에 저장합니다. 만약 찾지 못한다면 IF문에 의해, 알수 없는 도시명이라는 의미로 "Unknown City"라고 Label에 출력합니다. 그리고, 디폴트의 의미로 서울의 도시 ID로 초기화합니다.

전송 받은 ID를 cityID 배열에서 찾았다면 역시 IF문에 의해 배열에서 찾은 코드값으로 currentCityID를 세팅합니다. 물론 어차피 동일한 값을 이미 갖고 있는 상황이므로 생략해도 됩니다. 그리고 도시이름 배열에서 같은 위치에 있는 도시명을 찾아 Label에 출력합니다.

14번행은 줄바꿈을 위해 추가했습니다.

배열에서 서울의 ID값을 일부러 다르게 고친 후에 실행한 결과입니다. Unknown City로 출력되고 있습니다.

func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
    if elementName != "weather" && elementName == currentStart {
        if elementName == "cityid" {
            if let index = cityID.index(of: currentContent) {
                currentCityID = cityID[index]
                label.text = label.text! + cityName[index]
            } else {
                currentCityID = cityID[0]
                label.text = label.text! + "Unknown City"
            }
        } else if elementName == "country" {
            label.text = label.text! + "Country : " + currentContent
        } else if elementName == "longitude" {
            label.text = label.text! + "Longitude : " + currentContent
        } else if elementName == "latitude" {
            label.text = label.text! + "Latitude : " + currentContent
        } else if elementName == "sunrise" {
            label.text = label.text! + "Sun Rise : " + currentContent
        } else if elementName == "sunset" {
            label.text = label.text! + "Sun Set : " + currentContent
        } else if elementName == "temperature" {
            label.text = label.text! + "Temperature : " + currentContent
        } else if elementName == "humidity" {
            label.text = label.text! + "Humidity : " + currentContent
        } else if elementName == "pressure" {
            label.text = label.text! + "Pressure : " + currentContent
        }
        label.text = label.text! + "\n"
        }
}

나머지 태그에 대한 처리도 모두 추가하였습니다.

UIPickerView object 사용하기

PickerView는 아이폰에서 시간 설정이나 날짜 설정 등을 할때 자주 쓰는 UI 입니다. 우선 추가해서 보면 친숙할 겁니다.

우선 object library에서 UIPickerView를 드래그하여 화면 상단에 배치하였습니다.

UIPickerView 를 사용하기 위해서는 두 가지 선행 작업이 필요합니다. 첫 번째는 UIPickerView Data Source Protocol을 이용하여 PickerView의 규모를 결정하는 것이고, 두 번째는 UIPickerView Delegate Protocol을 이용하여 PickerView의 컨텐츠를 지정하는 것입니다.

UIPickerView Data Source는 두 개의 함수를 이용하여 각각 PickerView의 열과 행의 개수를 결정합니다. 두 함수의 리턴값이 열과 행의 개수가 되는데, 열은 연, 월, 일, 시, 분, 초와 같이 구분되는 항목을 말하며 Components라고 부릅니다. 행은 말 그대로 한 항목에서 선택할 수 있는 데이터의 모음입니다. 열(Component)이 "요일"이면 행(row)은 "월화수목금토일"이 되는 것을 말합니다.

UIPickerView Delegate는 하나의 함수를 이용하여 뷰에 표시되는 내용을 결정합니다. 우리가 눈으로 보고 선택하는 타이틀을 말하며, 행(row) 항목이 모여 있는 배열을 바인딩하면 됩니다. 여기까지 해야 사용할 준비가 끝나는데 실제론 아주 간단합니다.

class ViewController: UIViewController, XMLParserDelegate, UIPickerViewDelegate, UIPickerViewDataSource {

두 개의 프로토콜 이름은 UIPickerViewDelegate, UIPickerViewDataSourceclass 이며 이를 역시 클래스 정의 부분에 추가해 줍니다.

@IBOutlet var label: UILabel!
@IBOutlet var pickerView: UIPickerView!

Label과 마찬가지로 @IBOutlet 설정을 해줍니다. 직접 타이핑하든 끌어서 삽입하든 Connection 설정까지 확인해야 합니다.

override func viewDidLoad() {
    super.viewDidLoad()
    pickerView.delegate = self
    pickerView.dataSource = self
}

XML Parser Delegate와 마찬가지로 delegate와 dataSource에 대해 self로 설정합니다. 자신이 속한 클래스에서 처리하기 때문입니다. viewDidLoad() 함수는 Interface Builder에서 만든 화면 요소를 메모리에 로딩을 완료한 시점에 실행되는 함수입니다. 아직 화면에 보이지는 않고, 사전 작업이 필요할 때 이 함수내에서 자주 처리합니다.

func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
}

언급한대로 PickerView의 Data Source를 지정하려면 2개의 함수가 필요합니다. 역시 이미 만들어진 함수를 자동 완성을 이용하여 가져오면 됩니다. 첫 번째 함수는 Components의 개수를 지정하는 함수입니다. 1을 리턴하기 때문에 이 PickerView의 Components는 1개입니다. Component는 열의 개념으로 데이터 소스의 종류를 말합니다. 예를 들어, 연월일의 날짜를 지정하는 PickerView는 Components가 연, 월, 일 3개 입니다. 여기서는 도시 이름 하나만 보여지기 때문에 1로 리턴합니다.

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return cityName.count
}

두 번째 함수는 하나의 Component내에 행의 개수를 지정합니다. 예를 들어, Component가 "무지개색"이라면 7을 리턴하고, "월(month)"이라면 12를 리턴합니다. 선택할 수 있는 도시의 수가 일곱 개이므로 7을 리턴합니다. 도시 이름은 cityName[] 배열에 저장되어 있고, cityName.count를 이용하여 참조할 수 있습니다.

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return cityName[row]
}

UIPickerViewDelegate Protocol의 함수를 이용하여 표시되는 타이틀을 지정하는 부분입니다. 위에 두 함수를 통해 규모를 이미 정했기 때문에 몇 개의 항목을 가져올 지 알고 있습니다. 따라서 cityName[row]를 통해 cityName[0]부터 cityName[6]까지 바인딩하게 됩니다.

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    print(cityName[row])
    currentCityID = cityID[row]
}

PickerView에서 선택한 데이터를 처리하는 함수도 이 프로토콜을 이용합니다. 사용자가 PickerView를 돌려 데이터를 선택하면 이 함수에서 선택된 행의 인덱스를 정수값으로 넘겨주는데 인수중 row 변수에 담겨 있습니다. 도시명 배열과 바인딩되어 있기 때문에 항목들의 순서가 같아서 그대로 배열 인덱스로 사용하여 값을 구하면 됩니다.

첫 번째 행의 print(cityName[row]) 함수는 해당 인덱스(row)의 도시 이름을 콘솔에 테스트를 위해 출력해 주고, 두 번째줄에서 city ID값을 추출하여 currentCityID에 저장합니다.

실행한 모습입니다. 아직 서버를 향한 XML request에는 적용하지 않았지만, 도시 이름을 선택할 때마다 콘솔창에서 선택된 내용을 확인할 수 있습니다. 이로써 PickerView를 사용할 준비가 끝났습니다.

선택된 도시의 날씨 정보 가져오기

PickerView에서 데이터를 선택할 때마다 currentCityID에 선택된 도시의 City ID값이 저장되도록 구성하였습니다. 이제 서버 Request 메시지에 이 부분을 추가하도록 하겠습니다.

@IBAction func request(_ sender: UIButton) {
    label.text = "Weather Info\n"
    let urlString = "http://192.168.1.65/cityid=" + currentCityID
    let url: URL = URL(string: urlString)!
    print(url)

5번 행만 수정하면 끝입니다. 이전에는 주소만 보냈지만, 이제 cityid=currentCityID를 추가하여 보내도록 수정하였습니다.

void requestProcess(String requestLine) {
  int cityIdIndex = requestLine.indexOf("cityid");
  if (cityIdIndex != -1) {
    cityID = requestLine.substring(cityIdIndex + 7, cityIdIndex + 14);
  }
}

아두이노 스케치 소스입니다. 아이폰에서 보내는 City ID를 받아서 처리할 수 있도록 변경하였습니다. 바로 위 함수만 변경하면 완료됩니다.

위와 같이 실행하여 결과까지 확인하였습니다. 아두이노와 Xcode의 ViewController.swift 전체 소스는 아래쪽에 두겠습니다. 참고하세요.

이상입니다

Arduino 전체 소스

#include <SPI.h>
#include <WiFi101.h>
char ssid[] = "TURTLE";
char pass[] = "yesican1";
String cityID = "1835847"; // 기본값은 서울
String appID = "7b08dfe35b4273bbe63604c75573cacf"; // 각 계정의 APP ID
String selected1 = "";
String selected2 = "";
String selected3 = "";
String selected4 = "";
String selected5 = "";
String selected6 = "";
String selected7 = "";
bool tagInside = false;  // 태그 안쪽인지 바깥쪽인지 구별하는 변수
bool flagStartTag = false; // 스타트 태그인지 구별하는 변수
String currentTag = ""; // 현재 태그를 저장하기 위한 변수, 공백으로 초기화함
String currentData = ""; // 태그 사이의 컨텐츠를 저장하는 변수
String startTag = ""; // 현재 elements의 start tag 저장
String endTag = "";   // 현재 elements의 end tag 저장
String country = "";
String cityName = "";
String coordLon = "";
String coordLat = "";
String sunRise = "";
String sunSet = "";
String tempValue = "";
String humidValue = "";
String pressValue = "";
int status = WL_IDLE_STATUS;
char server[] = "api.openweathermap.org";
IPAddress ip;
WiFiServer Webserver(80); // Server 서비스를 위한 클래스 인스턴스
WiFiClient client;
void setup() {
  WiFi.setPins(8,7,4,2); 
  Serial.begin(9600);
  delay(1000);
  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
    // wait 2 seconds for connection:
    delay(2000);
  }
  Serial.println("Connected to wifi");
  OpenWeatherMap();
  Webserver.begin();
  ip = WiFi.localIP();
  Serial.print("To see this page in action, open a browser to http://");
  Serial.println(ip);
}
void loop() {
  WiFiClient Webclient = Webserver.available();
  if (Webclient) {
    Serial.println("new client");
    bool newLine = false;
    String currentLine = "";
    while (Webclient.connected()) {
      if (Webclient.available()) {
        char c = Webclient.read();
        Serial.write(c);
        if (c == '\n') {
          if (newLine) {
            Serial.println("Client Request Ended!");
            Serial.println("Weather Data Request!");
            OpenWeatherMap(); 
            Serial.println("Web page transfer Start!");
            Webclient.println("HTTP/1.1 200 OK");
            Webclient.println("Content-type:text/html");
            Webclient.println("Connection: close");
            Webclient.println();
            Webclient.print("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            Webclient.print("<weather>");
            Webclient.print("<cityid>");
            Webclient.print(cityID);
            Webclient.print("</cityid>");
            Webclient.print("<country>");
            Webclient.print(country);
            Webclient.print("</country>");
            Webclient.print("<longitude>");
            Webclient.print(coordLon);
            Webclient.print("</longitude>");
            Webclient.print("<latitude>");
            Webclient.print(coordLat);
            Webclient.print("</latitude>");
            Webclient.print("<sunrise>");
            Webclient.print(sunRise);
            Webclient.print("</sunrise>");
            Webclient.print("<sunset>");
            Webclient.print(sunSet);
            Webclient.print("</sunset>");
            Webclient.print("<temperature>");
            Webclient.print(tempValue);
            Webclient.print("</temperature>");
            Webclient.print("<humidity>");
            Webclient.print(humidValue);
            Webclient.print("</humidity>");
            Webclient.print("<pressure>");
            Webclient.print(pressValue);
            Webclient.print("</pressure>");
            Webclient.print("</weather>");
            break;
          } else {
            newLine = true; 
            if (currentLine.indexOf("HTTP/1.1") != -1) {
              requestProcess(currentLine);
            }
            currentLine = "";
          }
        } else if (c != '\r') {
          currentLine += c;
          newLine = false;
        }
      }
    } 
    Webclient.stop();
    Serial.println("client disonnected");
  }
}
void requestProcess(String requestLine) {
  int cityIdIndex = requestLine.indexOf("cityid");
  if (cityIdIndex != -1) {
    cityID = requestLine.substring(cityIdIndex + 7, cityIdIndex + 14);
  }
}
void OpenWeatherMap() { 
  Serial.println("\nStarting connection to server..."); 
  if (client.connect(server, 80)) {
    Serial.println("connected to server");
    String request = "GET /data/2.5/weather?id=";
    request += cityID;
    request += "&APPID=";
    request += appID;
    request += "&units=metric&mode=xml HTTP/1.1"; 
    client.println(request);
    client.println("Host: api.openweathermap.org");
    client.println("Connection: close");
    client.println();
  } 
  while (client.connected()) {
    while (client.available()) {
      char c = client.read(); 
      if (c == '<') {
        tagInside = true;
      } 
      if (tagInside) {
        currentTag += c;
      } else if (flagStartTag) {
        currentData += c;
      } 
      if (c == '>') {
        tagInside = false;
        if (currentTag.startsWith("</")) {
          flagStartTag = false;
          endTag = currentTag; 
          if (startTag.indexOf("country") != -1) {
            if (endTag.indexOf("country") != -1) {
              Serial.print("Country : ");
              Serial.println(currentData);
              country = currentData;
            }
          }
          currentData = "";
        } else {
          flagStartTag = true;
          startTag = currentTag;
          startTagProcessing();
        }
        currentTag = "";
      }
    }
  }
  Serial.println();
  Serial.println("disconnecting from server.");
  client.stop();
}
void startTagProcessing() {
  if (startTag.startsWith("<city")) {
    int attribName = startTag.indexOf("name=");
    if (attribName != -1) {
      cityName = startTag.substring(attribName + 6);
      int quote = cityName.indexOf("\"");
      cityName = cityName.substring(0, quote);
      Serial.println("City : " + cityName);
    }
  } else if (startTag.startsWith("<coord")) {
    int attribLon = startTag.indexOf("lon=");
    if (attribLon != -1) {
      coordLon = startTag.substring(attribLon + 5);
      int quote = coordLon.indexOf("\"");
      coordLon = coordLon.substring(0, quote);
      Serial.println("Longitude : " + coordLon);
    }
    int attribLat = startTag.indexOf("lat=");
    if (attribLat != -1) {
      coordLat = startTag.substring(attribLat + 5);
      int quote = coordLat.indexOf("\"");
      coordLat = coordLat.substring(0, quote);
      Serial.println("Latitude : " + coordLat);
    }
  } else if (startTag.startsWith("<sun")) {
    int attribTime = startTag.indexOf("rise=");
    if (attribTime != -1) {
      String riseHour = startTag.substring(attribTime + 17, attribTime + 19);
      String riseMin = startTag.substring(attribTime + 20, attribTime + 22);
      int tempValue = riseHour.toInt();
      tempValue -= 15;
      riseHour = String(tempValue);
      Serial.println("Sun Rise : " + riseHour + ":" + riseMin);
      sunRise = riseHour + ":" + riseMin;
    }
    attribTime = startTag.indexOf("set=");
    if (attribTime != -1) {
      String setHour = startTag.substring(attribTime + 16, attribTime + 18);
      String setMin = startTag.substring(attribTime + 19, attribTime + 21);
      int tempValue = setHour.toInt();
      tempValue += 9;
      setHour = String(tempValue);
      Serial.println("Sun Set : " + setHour + ":" + setMin);
      sunSet = setHour + ":" + setMin;
    }
  } else if (startTag.startsWith("<temperature")) {
    int attribValue = startTag.indexOf("value=");
    if (attribValue != -1) {
      tempValue = startTag.substring(attribValue + 7);
      int quote = tempValue.indexOf("\"");
      tempValue = tempValue.substring(0, quote);
      Serial.println("Temperature : " + tempValue);
    }
  } else if (startTag.startsWith("<humidity")) {
    int attribValue = startTag.indexOf("value=");
    if (attribValue != -1) {
      humidValue = startTag.substring(attribValue + 7);
      int quote = humidValue.indexOf("\"");
      humidValue = humidValue.substring(0, quote);
      Serial.println("Humidity : " + humidValue + "%");
    }
  }else if (startTag.startsWith("<pressure")) { 
    int attribValue = startTag.indexOf("value=");
    if (attribValue != -1) {
      pressValue = startTag.substring(attribValue + 7);
      int quote = pressValue.indexOf("\"");
      pressValue = pressValue.substring(0, quote);
      Serial.println("Pressure : " + pressValue + " hPa");
    }
  }
}

ViewController.swift 전체 소스

//
//  ViewController.swift
//  arduinoWeather
//
//  Created by turtle on 2017. 8. 25..
//  Copyright © 2017년 turtleShell. All rights reserved.
//
import UIKit
class ViewController: UIViewController, XMLParserDelegate, UIPickerViewDelegate, UIPickerViewDataSource {
    var parser = XMLParser() 
    var currentStart = ""
    var currentContent = "" 
    let cityID = ["1835847", "1838519", "1835327", "1843561", "1841808", "1835224", "1833742"]
    let cityName = ["서울특별시", "부산광역시", "대구광역시", "인천광역시", "광주광역시", "대전광역시", "울산광역시"] 
    var currentCityID = "1835847" 
    @IBOutlet var label: UILabel!
    @IBOutlet var pickerView: UIPickerView! 
    override func viewDidLoad() {
        super.viewDidLoad() 
        pickerView.delegate = self
        pickerView.dataSource = self 
    }
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
    @IBAction func request(_ sender: UIButton) { 
        label.text = "Weather Info\n" 
        let urlString = "http://192.168.1.65/cityid=" + currentCityID 
        let url: URL = URL(string: urlString)! 
        print(url) 
        parser = XMLParser(contentsOf: url)!
        parser.delegate = self 
        let result: Bool = parser.parse() 
        if result {
            print("Parsing success!")
        } else {
            print("Parsing fail!")
        }
    } 
    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { 
        currentStart = elementName
    } 
    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) { 
        if elementName != "weather" && elementName == currentStart { 
            if elementName == "cityid" { 
                if let index = cityID.index(of: currentContent) { 
                    currentCityID = cityID[index]
                    label.text = label.text! + cityName[index] 
                } else { 
                    currentCityID = cityID[0]
                    label.text = label.text! + "Unknown City"
                } 
            } else if elementName == "country" { 
                label.text = label.text! + "Country : " + currentContent 
            } else if elementName == "longitude" { 
                label.text = label.text! + "Longitude : " + currentContent 
            } else if elementName == "latitude" { 
                label.text = label.text! + "Latitude : " + currentContent 
            } else if elementName == "sunrise" { 
                label.text = label.text! + "Sun Rise : " + currentContent 
            } else if elementName == "sunset" { 
                label.text = label.text! + "Sun Set : " + currentContent 
            } else if elementName == "temperature" { 
                label.text = label.text! + "Temperature : " + currentContent 
            } else if elementName == "humidity" { 
                label.text = label.text! + "Humidity : " + currentContent 
            } else if elementName == "pressure" { 
                label.text = label.text! + "Pressure : " + currentContent 
            } 
            label.text = label.text! + "\n"
        }
    } 
    func parser(_ parser: XMLParser, foundCharacters string: String) { 
        currentContent = string
    } 
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    } 
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return cityName.count
    } 
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return cityName[row]
    } 
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        print(cityName[row])
        currentCityID = cityID[row]
    }
}

Comments