본문 바로가기

개발자/Arduino

OpenWeatherMap 날씨 정보를 OLED 에 디스플레이, Nano 33 IoT

반응형

 

 

Nano 33 IoT 보드를 사용하여 원하는 도시의 온도와 습도 정보를 보여줍니다. 날씨 정보를 뽑아오는 상세한 설명은 참고 자료의 사이트를 참고합니다. 세계 어떤 지역의 날씨를 보여줄 수 있습니다. 아래 첨부한 잘 돌아가는 코드를 참고하세요.

 

보완할 점

 

1. 장소를 옮길 때마다 매번 인터넷 WiFi 변경을 바꿔주고 펌웨어를 업로드해야 한다. 블루투스로 연결하여 설정을 바꿔주면 좋겠다. 설정 정보는 wifi 접속 정보, 국가, 도시, 보여줄 정보 - 온도, 습도, 압력, 바람 등-를 사용자가 선택하게.

 

2. 예쁜 기상 정보 아이콘은 Weather Icons란 사이트를 참고한다.

 

3. display 화면이 현재는 ssd1306 oled인데 너무 작고 정보가 적으므로 큰 디스플레이 화면으로 변경

 

아래 잘 돌아가는 코드를 참고합니다.

 

WiFi 환경을 잡아주는 arduino_secret.h 파일을 인터넷 환경에 맞도록 수정한다.

 

#define SECRET_SSID "FO****RCM"
#define SECRET_PASS "166******10350"

 

API 키를 받아와 OpenweatherMap 사이트에서 정보를 불러와 OLED에 나타내는 코드입니다. 25라인 보면 발급받은 API 키를 이용해 도시 설정을 바꾸어 주면 됩니다. 예제에서는 그린란드의 qaanaaq 란 도시의 온도와 습도를 보여줍니다. 결과 화면을 아래에 첨부합니다.

 

/*
 * Rui Santos 
 * Complete Project Details http://randomnerdtutorials.com
 * Based on the Arduino Ethernet Web Client Example
 * and on the sketch "Sample Arduino Json Web Client" of the Arduino JSON library by Benoit Blanchon (bblanchon.github.io/ArduinoJson)
 */

#include <ArduinoJson.h>
#include <SPI.h>
#include <WiFiNINA.h>

#include <Adafruit_GFX.h>      // include Adafruit graphics library
#include <Adafruit_SSD1306.h>  // include Adafruit SSD1306 OLED display driver

#define OLED_RESET  4    // define display reset pin
Adafruit_SSD1306 display(OLED_RESET);

//EthernetClient client;
WiFiClient client;

// Name address for Open Weather Map API
const char* server = "api.openweathermap.org";

// Replace with your unique URL resource
//const char* resource = "/data/2.5/weather?q=seoul,KR&APPID=34b3527445f4bb5a2b~~~~~~~~~~~~~~";
//const char* resource = "/data/2.5/weather?q=busan,KR&APPID=34b3527445f4bb5a2b~~~~~~~~~~~~~~";
const char* resource = "/data/2.5/weather?q=qaanaaq&APPID=34b3527445f4bb5a2b8be~~~~~~~~~~~~~~";

// How your resource variable should look like, but with your own COUNTRY CODE, CITY and API KEY (that API KEY below is just an example):
//const char* resource = "/data/2.5/weather?q=Porto,pt&appid=bd939aa3d23ff33d3c8f5dd1";

const unsigned long HTTP_TIMEOUT = 10000;  // max respone time from server
const size_t MAX_CONTENT_SIZE = 512;       // max size of the HTTP response


#include "arduino_secrets.h" 
///////please enter your sensitive data in the Secret tab/arduino_secrets.h
char ssid[] = SECRET_SSID;        // your network SSID (name)
char pass[] = SECRET_PASS;    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;

// The type of data that we want to extract from the page
struct clientData {
  char temp[8];
  char humidity[8];
};

// ARDUINO entry point #1: runs once when you press reset or power the board
void setup() {
  Serial.begin(9600);
  //while (!Serial) { ; } //wait for serial port to initialize

  initial_oled();
  
  Serial.println("Serial ready");
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to wifi");
  printWifiStatus();
}

// ARDUINO entry point #2: runs over and over again forever
void loop() {
  if(connect(server)) {
    if(sendRequest(server, resource) && skipResponseHeaders()) {
      clientData clientData;
      if(readReponseContent(&clientData)) {
        printclientDatatoserial(&clientData);
        printclientDatatooled(&clientData);        
      }
    }
  }
  disconnect();
  wait();
}

// Open connection to the HTTP server
bool connect(const char* hostName) {
  Serial.print("Connect to ");
  Serial.println(hostName);

  bool ok = client.connect(hostName, 80);

  Serial.println(ok ? "Connected" : "Connection Failed!");
  return ok;
}

// Send the HTTP GET request to the server
bool sendRequest(const char* host, const char* resource) {
  Serial.print("GET ");
  Serial.println(resource);

  client.print("GET ");
  client.print(resource);
  client.println(" HTTP/1.1");
  client.print("Host: ");
  client.println(host);
  client.println("Connection: close");
  client.println();

  return true;
}

// Skip HTTP headers so that we are at the beginning of the response's body
bool skipResponseHeaders() {
  // HTTP headers end with an empty line
  char endOfHeaders[] = "\r\n\r\n";

  client.setTimeout(HTTP_TIMEOUT);
  bool ok = client.find(endOfHeaders);

  if (!ok) {
    Serial.println("No response or invalid response!");
  }
  return ok;
}

// Parse the JSON from the input string and extract the interesting values
// Here is the JSON we need to parse
/*{
    "coord": {
        "lon": -8.61,
        "lat": 41.15
    },
    "weather": [
        {
            "id": 800,
            "main": "Clear",
            "description": "clear sky",
            "icon": "01d"
        }
    ],
    "base": "stations",
    "main": {
        "temp": 296.15,
        "pressure": 1020,
        "humidity": 69,
        "temp_min": 296.15,
        "temp_max": 296.15
    },
    "visibility": 10000,
    "wind": {
        "speed": 4.6,
        "deg": 320
    },
    "clouds": {
        "all": 0
    },
    "dt": 1499869800,
    "sys": {
        "type": 1,
        "id": 5959,
        "message": 0.0022,
        "country": "PT",
        "sunrise": 1499836380,
        "sunset": 1499890019
    },
    "id": 2735943,
    "name": "Porto",
    "cod": 200
}*/

bool readReponseContent(struct clientData* clientData) {
  // Compute optimal size of the JSON buffer according to what we need to parse.
  // See https://bblanchon.github.io/ArduinoJson/assistant/
  const size_t bufferSize = JSON_ARRAY_SIZE(1) + JSON_OBJECT_SIZE(1) + 
      2*JSON_OBJECT_SIZE(2) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + 
      JSON_OBJECT_SIZE(6) + JSON_OBJECT_SIZE(12) + 390;
  DynamicJsonBuffer jsonBuffer(bufferSize);

  JsonObject& root = jsonBuffer.parseObject(client);

  if (!root.success()) {
    Serial.println("JSON parsing failed!");
    return false;
  }

  // Here were copy the strings we're interested in using to your struct data
  strcpy(clientData->temp, root["main"]["temp"]);
  strcpy(clientData->humidity, root["main"]["humidity"]);
  // It's not mandatory to make a copy, you could just use the pointers
  // Since, they are pointing inside the "content" buffer, so you need to make
  // sure it's still in memory when you read the string

  return true;
}

// Print the data extracted from the JSON
void printclientDatatoserial(const struct clientData* clientData) {

  Serial.println(clientData->temp);
  Serial.println(clientData->humidity);
    
  Serial.print("Temp = ");
  String receivedTemp = clientData->temp;
  Serial.print(receivedTemp.toFloat()-273.15);
  Serial.println(" ℃");
  Serial.print("Humidity = ");
  Serial.print(clientData->humidity);
  Serial.println(" %");
}

char _readydatatoOled[8];

void printclientDatatooled(const struct clientData* clientData) {
  String receivedTemp = clientData->temp;
  float tCelsius = receivedTemp.toFloat()-273.15;
  display.setCursor(23, 10);
  display.print(String(tCelsius) + " C");
  display.setCursor(23, 30);
  display.print(String(clientData->humidity) + " /");

  display.drawCircle(76, 12, 2, WHITE);
  display.drawCircle(60, 32, 2, WHITE); 
  display.drawCircle(70, 42, 2, WHITE); 
  
  display.display();
}

// Close the connection with the HTTP server
void disconnect() {
  Serial.println("Disconnect");
  client.stop();
}

// Pause for a 1 minute
void wait() {
  Serial.println("Wait 60 seconds");
  delay(60000);
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your board's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

void initial_oled()
{
  //initialize the SSD1306 OLED display with I2C address = 0x3D
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

  // clear the display buffer.
  display.clearDisplay();
 
  display.setTextSize(1);   // text size = 1
  display.setTextColor(WHITE, BLACK);  // set text color to white and black background
  display.setCursor(15, 0);            // move cursor to position (15, 0) pixel
  display.print("Seoul Weather");
  display.display();        // update the display
  display.setTextSize(2);   // text size = 2
}

 

결과 사진

 

qaanaaq 도시의 온도와 습도를 보여준다.

 

 

참고사이트

OpenWeatherMap을 이용한 날씨 API를 사용해보자 

222 Weather Themed Icons and CSS 

 

 

 

반응형

캐어랩 고객 지원

취업, 창업의 막막함, 외주 관리, 제품 부재!

당신의 고민은 무엇입니까? 현실과 동떨어진 교육, 실패만 반복하는 외주 계약, 아이디어는 있지만 구현할 기술이 없는 막막함.

우리는 알고 있습니다. 문제의 원인은 '명확한 학습, 실전 경험과 신뢰할 수 있는 기술력의 부재'에서 시작됩니다.

이제 고민을 멈추고, 캐어랩을 만나세요!

코딩(펌웨어), 전자부품과 디지털 회로설계, PCB 설계 제작, 고객(시장/수출) 발굴과 마케팅 전략으로 당신을 지원합니다.

제품 설계의 고수는 성공이 만든 게 아니라 실패가 만듭니다. 아이디어를 양산 가능한 제품으로!

귀사의 제품을 만드세요. 교육과 개발 실적으로 신뢰할 수 있는 파트너를 확보하세요.

지난 30년 여정, 캐어랩이 얻은 모든 것을 함께 나누고 싶습니다.

카카오 채널 추가하기

카톡 채팅방에서 무엇이든 물어보세요

당신의 성공을 위해 캐어랩과 함께 하세요.

캐어랩 온라인 채널 바로가기

캐어랩