제작 목적

오늘의 날씨를 손쉽게 확인하기 위함.

외출시 굳이 날씨를 찾아보지 않아도 비가 오는지 여부를 알 수 있으면 좋겠다는 생각에 만듦.

(하지만 지금 버전은 현재 날씨와 온도까지만을 출력함. 추후 업그레이드 예정)


준비물

아두이노 메가 2560

esp8266(WiFi를 위해 필요함)

캐릭터LCD(일단은 16x2를 사용. 크면 클수록 좋음)

브레드보드

점퍼와이어


API를 받아오는 곳(가입 후 인증키를 발급받아야 함)

http://openweathermap.org


구동 사진

clcd 틀은 3d프린터로 뽑은 것


소스코드


#include <Wire.h> 

#include <LiquidCrystal_I2C.h>


LiquidCrystal_I2C lcd(0x3f,20,4);


#define _SS_MAX_RX_BUFF 512

#define ssid "공유기의 SSID" // ssid

#define serviceKey String("오픈웨더맵에서 발급받은 서비스키") // serviceKey

#define password "공유기의 비밀번호" // password

#define weatherReqInterval 3600000 // 60초 * 60분 * 1000(밀리세컨드)


int cmdSize = 0;

String rcvbuf;

String weatherStr;

String tempStr;

float tempFloat;

boolean weatherFlag = false;

boolean tempFlag = false;

boolean weatherDisp = false;

boolean tempDisp = false;

unsigned long prevConMillis = 0;




void setup(void)

{

  Serial.begin(9600);

  Serial1.begin(9600);

  pinMode(7, INPUT_PULLUP);

  pinMode(6, INPUT_PULLUP);

  lcd.init();

  lcd.backlight();

  lcd.setCursor(0,0);

  lcd.print("connecting...");

  connectWifi();

  weatherReq();

}




void loop(void)

{

  if(millis() - prevConMillis > weatherReqInterval){

    weatherReq();

  }

  while(Serial1.available())

  {

    if(rcvbuf.endsWith("\"description\":\"")){

      weatherFlag = true;

      weatherStr = "";

    }


    if(rcvbuf.endsWith("\"temp\":")){

      tempFlag = true;

      tempStr = "";

    }

    

    char c = Serial1.read();

    //Serial.write(c);

    if(c != NULL){

      rcvbuf += c;

    }


    if(weatherFlag){

      if(c != '\"'){

        weatherStr += c;

      }else{

        weatherFlag = false;

        weatherDisp = true;

      }

    }


    if(tempFlag){

      if(c != ','){

        tempStr += c;

      }else{

        tempFloat = tempStr.toFloat() - 273.0;

        tempFlag = false;

        tempDisp = true;

      }

    }

  }

  

  if(tempDisp && weatherDisp){

    Serial.println(weatherStr);

    Serial.println(tempFloat);

    lcd.setCursor(0,0);

    lcd.print("                    ");

    lcd.setCursor(0,0);

    lcd.print(weatherStr);


    lcd.setCursor(0,1);

    lcd.print("                    ");

    lcd.setCursor(0,1);

    lcd.print(tempFloat);


    weatherDisp = false;

    tempDisp = false;

  }

}



void weatherReq()

{

  //String str = "GET /data/2.5/weather?lat=37.56826&lon=126.977829&APPID=" + serviceKey;

  String str = "GET /data/2.5/weather?q=Euijeongbu,kr&&APPID=" + serviceKey;

  str.concat(" HTTP/1.1\r\nHost:api.openweathermap.org\r\nConnection: close\r\n\r\n");

  

  cmdSize = str.length();

  Serial1.println("AT+CIPSTART=\"TCP\",\"api.openweathermap.org\",80");

  delay(500);

  Serial1.print("AT+CIPSEND=");

  delay(500);

  Serial1.println(cmdSize);

  delay(500);

  Serial1.println(str);

  prevConMillis = millis();

}




void connectWifi()

{

  Serial1.println("AT+CWMODE=1");

  delay(500);

  while(Serial1.available()){

    Serial.write(Serial1.read());

  }

  Serial1.println("AT+CIPMUX=0");

  delay(500);

  while(Serial1.available()){

    Serial.write(Serial1.read());

  }

  Serial1.print("AT+CWJAP=\"");

  Serial1.print(ssid);

  Serial1.print("\",\"");

  Serial1.print(password);

  Serial1.println("\"");

  delay(6000);

  while(Serial1.available()){

    Serial.write(Serial1.read());

  }

}

간단한 동작 설명..

setup에서 와이파이를 공유기와 연결하고 오픈웨더맵API를 통해 서버에 날씨 데이터를 1회 요청한다.

다음은 루프를 돌면서 1시간에 1회씩 서버에 반복적으로 요청을 하게 된다.

루프 내에서는 동시에 while문을 통해 시리얼 통신으로 뭔가가 들어올 때마다 처리를 하게 된다.

(이 프로그램에선 날씨 데이터를 요청(req)했으니 당연히 response로 뭔가가 올거다. HTTP헤더와 함께 JSON이 날아오게 되는데, JSON을 파싱하는 API를 사용하면 자원을 많이 먹을 수 있기 때문에 직접 실시간으로 파싱을 한다.)

description 키워드의 뒷부분에 날씨 정보가 들어있고, temp키워드의 뒷부분에 온도 정보가 있기 때문에 해당 부분만 추출한다.

그 후 두가지 정보가 모두 추출되었다면 캐릭터lcd로 정보를 뿌려주는 것으로 동작을 끝낸다.

이후 이 과정을 무한 반복...



향후 보완할 점

현재 날씨만 나오기 때문에 주간 날씨가 나오도록 변경하려고 함.

GLCD로 변경하거나 LED 다수를 사용하여 필요한 정보를 표시하도록 변경할까 한다.

미세먼지 여부도 출력하면 좋을거 같다.

3d프린터로 외형도 만들면 좋지만, 일단은 보류.

왜냐면 Wemos D1으로 바꾸면 크기가 훨씬 줄어들기 때문.

  • 2017.09.30 14:30

    비밀댓글입니다

  • 2017.09.30 14:31

    비밀댓글입니다