정보나눔

오픈소스하드웨어 프로젝트에 대한 다양한 정보를 나누는 공간입니다.

구름 조명(완성) 제작중 질문 드립니다
김동환 | 2016-06-07

http://kocoafab.cc/make/view/564

위 주소에서 구름 조명 완성본을 보고 간단하게 실험을 해볼려 하는대

전원 버튼을 누르고 날시 정보 받아 온 것을 네오 픽셀  LED로 색을 출력하고 무드등까지 하였습니다

그런대 무드등으로 되었때  버튼을 누르지 않았는대 자동으로 데이터 요청을 하는건지 시리얼 모니터 창에 계속 오류가 발생 하고

버튼 제어가 되지를 않았습니다.

프로그렘 소스는 위주소에서 첨부되었던 소스를 그대로 사용 하였습니다.

어느 부분에서 문제가 발생한건지 궁금하여 질문드립니다.

아래의 사진은 시리얼 모니터 오류 사진입니다

프로필사진

Klant 2016-06-08 11:57:51

안녕하세요! 김동환님!

테스트를 진행한 결과 최초 날씨 데이터 파싱 버튼을 눌렀을 때는 파싱된 데이터에 따라 LED가 제어되고, 

두번째부터는 데이터는 들어오나 데이터에 맞게 LED 제어가 동작되지 않고, 세번째부터는 request 에러가 나네요. 

우선 두번째부터 날씨 데이터에 따라 제대로 파싱이 되지 않는 부분에 대해서는 CurrentLine에 들어오는 데이터가 꼬였거나, 아니면 제대로 들어오지 않았기 때문이라고 유추가 되는데요. 

openweathermap에서 받아온 데이터를 CurrentLine에 저장하게 되는데 저장 과정에서 데이터가 꼬이는 것을 막기 위해 날씨 데이터 파싱 버튼을 눌렀을 때 CurrentLine을 초기화 하도록 소스를 조금 변경하였습니다. 

테스트 결과 잘 작동하니 그대로 사용하시면 될 것 같네요! 

 

 

#include <Adafruit_NeoPixel.h>
#include <avr/power.h>

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

char ssid[] = "AndroidHotspot5085";         //와이파이 ID
char pass[] = "wmfwmfdl3";     //와이파이 비밀번호
String location = "seoul";          //날씨를 가져오고자 하는 지역 선택

WiFiClient client;
char server[] = "api.openweathermap.org";

IPAddress hostIp;

//neopixel LED를 10번핀에 연결
#define PIN 10
Adafruit_NeoPixel strip = Adafruit_NeoPixel(10, PIN, NEO_GRB + NEO_KHZ800);     //neopixel LED의 개수 설정 및 선언

String currentLine = "";            //서버에서 전송된 데이터 String 저장
String codeString = "";             //날씨 코드 저장 변수
boolean readingCode = false;        //코드 데이터가 있는지 여부 판단

int redVal;                         //RGB LED red 값 변수
int greenVal;                       //RGB LED green 값 변수
int blueVal;                        //RGB LED blue 값 변수

int weatherButton = 9;              //날씨 데이터 파싱 동작을 위한 버튼을 9번에 연결
int powerButton = 8;                //조명 on, off 동작을 위한 버튼을 8번에 연결

//on, off 버튼 토글 동작을 위한 변수
int oneTimeFlag;
boolean onOffStatus;

//날씨 파싱 동작을 위한 변수
boolean parsingStart = false;

int weatherCode;
int temp = 0;

void setup() {
  //버튼 셋팅(INPUT 설정)f
  pinMode(powerButton, INPUT_PULLUP);
  pinMode(weatherButton, INPUT_PULLUP);

  //neopixel setting
#if defined (__AVR_ATtiny85__)
  if (F_CPU == 16000000) clock_prescale_set(clock_div_1);
#endif

  strip.begin();
  strip.show();

  //각 변수에 정해진 공간 할당
  currentLine.reserve(100);
  codeString.reserve(10);

  Serial.begin(115200);

  //Wi-Fi 연결 시도
  delay(10);
  Serial.println("Connecting to WiFi....");
  WiFi.begin(ssid, pass);
  Serial.println("Connect success!");
  Serial.println("Waiting for DHCP address");
  while (WiFi.localIP() == INADDR_NONE) {
    Serial.print(".");
    delay(300);
  }
  printWifiData();  //Wi-Fi 정보 출력
  readyLED();       //Wi-Fi 연결 후 준비가 완료되었다면 초록빛 dimming

}

void loop() {
  /*on, off 버튼 토글 설정
   off : onOffStatus = 0
   on : onOffStatus = 1*/

  int i = digitalRead(weatherButton);            //날씨 버튼 상태를 변수 i에 저장

  if (digitalRead(powerButton) == LOW) { //power 버튼이 눌러지면 onOffstatus의 상태값 토글
    if (oneTimeFlag == 0) {
      oneTimeFlag = 1;
      onOffStatus = !onOffStatus;
    }
  }
  else {
    oneTimeFlag = 0;
  }


  if (onOffStatus == 0) {                                //onOffStatus의 상태가 0이면
    for (int i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, 0, 0, 0);
      strip.show();
    }
  }

  //날씨 데이터 파싱 및 RGB led 색상 조절 모드
  else {
    if (i == 0) {                                        //weatherButton의 상태가 0이라면
      parsingStart = true;     //parsingStart의 상태값 변경
    }

    while (parsingStart) {      //parsingStart의 상태값이 참일동안
      currentLine = "";
      connectToServer();                                  //서버 연결(openweathermap API에 날씨데이터 호출)
      if (client.connected()) {     //클라이언트에 연결되어 있다면
        delay(3000); //**
        while (client.available()) { //클라이언트에 들어온 데이터가 있다면
          char inChar = client.read();                   //들어온 데이터를 inChar에 저장
          currentLine += inChar;                 //inChar에 저장된 char 변수는 currenLine에 저장됨
          Serial.print(inChar);
          if (inChar == '\n') {                          //줄바꿈(\n) 문자열이 전송되면 데이터를 저장하지 않음
            currentLine = "";
          }

          //날씨 코드 데이터가 전송되었는지 확인
          if (currentLine.endsWith("<weather number=")) { //currentLine의 string이 <weather number=로 끝났다면
            readingCode = true;                            //날씨 코드 데이터를 받을 준비를 한다
            codeString = "";
            Serial.println("check");
          }
          if (readingCode) {
            if (inChar != 'v') {                         //inChar string에 v가 전송될 때까지
              codeString += inChar;                      //codeString에 저장
            }
            else {                                       //전송된 문자가 v라면
              readingCode = false;                       //저장 중지
              weatherCode = getInt(codeString);          //저장한 날씨 코드 string을 integer로 변환
              //Serial.print("weather : ");                //시리얼 모니터로 날씨 코드 출력
              //Serial.println(codeString);
            }
          }
        }
      }
      else {
        Serial.println("connect fail");           //클라이언트에 연결되지 않았다면 시리얼 모니터창에 connect fail 출력
        errorLED();                               //클라이언트에 연결되지 않았다면 빨간빛 dimming
        //weatherCode=0;
      }

      //날씨 코드 분류
      if (weatherCode > 299 && weatherCode < 532) {  //rainny
        rainnyLED();
      }
      else if (weatherCode > 599 && weatherCode < 623) { //snow
        snowLED();
      }
      else if (weatherCode > 700 && weatherCode < 782) { //mist
        cloudyMistLED();
      }
      else if (weatherCode > 799 && weatherCode < 802) { //clear and sunny
        clearweatherLED();
      }
      else if (weatherCode > 801 && weatherCode < 805) { //cloudy
        cloudyMistLED();
      }

      parsingStart = false;             //날씨 데이터를 파싱하고 LED로 날씨를 표현한 후 상태값 변경
      weatherCode = 0;
    }


    //조명모드
    redVal = map(analogRead(A0), 0, 1023, 0, 255);
    greenVal = map(analogRead(A1), 0, 1023, 0, 255);
    blueVal = map(analogRead(A2), 0, 1023, 0, 255);

    for (int i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, redVal, greenVal, blueVal);
      strip.show();
    }


  }
}

//Wi-Fi 서버 연결 함수
void connectToServer() {
  client.stop();
  if (client.connect(server, 80)) {
    Serial.println("connecting...");
    // send the HTTP PUT request:
    client.println("GET /data/2.5/weather?q=" + location + "&mode=xml&APPID=ece3f16628536ea9b95ea7adc2a5b595");
    client.println("HOST: api.openweathermap.org\n");
    client.println("User-Agent: ArduinoWiFi/1.1");
    client.println("Connection: close");
    client.println();
  }
  else {
    Serial.println("connection failed");
    errorLED();         //서버에 연결하지 못했다면 빨간빛 dimming
  }
}

//Wi-Fi data 출력
void printWifiData() {
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // Wi-Fi 쉴드 IP 주소 출력
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // 수신 신호 강도 출력
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

//정수 변환을 위한 함수
int getInt(String input) {
  int i = 2;
  while (input[i] != '"') {
    i++;
  }
  input = input.substring(2, i);
  char carray[20];
  input.toCharArray(carray, sizeof(carray));
  temp = atoi(carray);
  return temp;
}


//LED 패턴 함수
//clear and sunny, 무지개빛 출력
void clearweatherLED() {
  uint16_t i, j;
  for (j = 0; j < 256; j++) {
    for (i = 0; i < strip.numPixels(); i++) {
      strip.setPixelColor(i, Wheel((i + j) & 255));
    }
    strip.show();
    delay(20);
  }
}


//cloudy and mist, 흰색빛으로 dimming
void cloudyMistLED() {
  uint16_t i, j;
  for (int k = 0; k < 3; k++) {
    for (j = 0; j < 256; j++) {
      for (i = 0; i < strip.numPixels(); i++) {
        int sum = i + j;
        map(sum, 0, 300, 120, 190);
        strip.setPixelColor(i, Wheel(sum), Wheel(sum), Wheel(sum));
      }
      strip.show();
      delay(8);
    }
  }
}

//rainny and thunder, 노란색 빛으로 dimming후 blink
void rainnyLED() {
  uint16_t i, j;
  for (int k = 0; k < 2; k++) {
    for (j = 0; j < 256; j++) {
      for (i = 0; i < strip.numPixels(); i++) {
        int sum = i + j;
        map(sum, 0, 300, 120, 190);
        strip.setPixelColor(i, Wheel(sum), Wheel(sum), 0);
      }
      strip.show();
      delay(7);
    }
  }
  theaterChase(strip.Color(255, 255, 0), 40);
}

//snow, 흰색으로 theaterChase
void snowLED() {
  for (int j = 0; j < 7; j++) { //do 10 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (int i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, strip.Color(255, 255, 255));  //turn every third pixel on
        delay(30);
      }
      strip.show();
      delay(30);
      for (int i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, 0);      //turn every third pixel off
      }
    }
  }
}

//connect error, 빨간색 빛으로 dimming
void errorLED() {
  uint16_t i, j;
  for (int k = 0; k < 3; k++) {
    for (j = 0; j < 256; j++) {
      for (i = 0; i < strip.numPixels(); i++) {
        int sum = i + j;
        map(sum, 0, 300, 120, 190);
        strip.setPixelColor(i, Wheel(sum), 0, 0);
      }
      strip.show();
      delay(2);
    }
  }
}

//ready, 녹색 빛으로 dimming
void readyLED() {
  uint16_t i, j;
  for (j = 0; j < 256; j++) {
    for (i = 0; i < strip.numPixels(); i++) {
      int sum = i + j;
      map(sum, 0, 300, 120, 190);
      strip.setPixelColor(i, 0, Wheel(sum), 0);
    }
    strip.show();
    delay(8);
  }
}


uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if (WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  } else if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  } else {
    WheelPos -= 170;
    return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
  }
}

void theaterChase(uint32_t c, uint8_t wait) {
  for (int j = 0; j < 10; j++) { //do 10 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (int i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, c);  //turn every third pixel on
      }
      strip.show();

      delay(wait);

      for (int i = 0; i < strip.numPixels(); i = i + 3) {
        strip.setPixelColor(i + q, 0);      //turn every third pixel off
      }
    }
  }
}

이전글   |    싸이클 다시 질문드립니다. ㅜ 2016-06-07
다음글   |    아두이노 메가에서 TFT LCD출력에 관하여 문의드립니다. ... 2016-06-07