summaryrefslogtreecommitdiff
path: root/weather.cpp
blob: e76e462e26192bdd1f1fc5f2976bf48cf55b65bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include "weather.h"

//#define DEBUG

#define HTTP_TIMEOUT 5000  // ms
#define DOWNLOADSIZE 1100  // http buffer size, *should* be enough for a cnt=2 request
#define JSONSIZE 1500  // json buffer size, for a cnt=2 request
// ^ be careful with counter over/underflows!

#error "Specify an OpenWeatherMap API key and delete this line."
#define CITYID "YOURCITYID"
#define APIKEY "YOURAPIKEY"

#define APIHOST "api.openweathermap.org"
#define APIPATH "/data/2.5/forecast?id=" CITYID "&appid=" APIKEY "&cnt=2"
// "cnt=2" for 3 hour forecast

// queries OWM for the 3-hour-forecast, returns icon code
// see http://openweathermap.org/weather-conditions for codes
String getWeatherStatus() {
#ifdef DEBUG
  Serial.println("Requesting weather data.");
#endif

  WiFiClient cli;
  cli.connect(APIHOST, 80);
  cli.println("GET " APIPATH " HTTP/1.1");
  cli.println("Host: " APIHOST);
  cli.println("Connection: close\r\n");

#ifdef DEBUG
  Serial.println("Sent request: " APIHOST APIPATH);
#endif

  unsigned int timeoutTimer = HTTP_TIMEOUT;
  boolean gotHeaders = false;

  // skip headers
  while (cli.connected() && timeoutTimer-- && !gotHeaders) {
    while (cli.available()) {
      String line = cli.readStringUntil('\n');
      if (line == "\r") {
        gotHeaders = true;
        break;
      }
    }
    delay(1);
  }
  if (!gotHeaders) {
#ifdef DEBUG
    Serial.println("Did not receive headers.");
#endif
    cli.stop();
    if (!cli.connected()) {
#ifdef DEBUG
      Serial.println("Connection was reset.");
#endif
    }
    return "-1";
  }

  // read response into char array
  char response[DOWNLOADSIZE];
  unsigned int buffPointer = 0;
  boolean jsonStarted = false;
  int charsSinceJsonEnd = 0;
  while (cli.connected() && timeoutTimer-- && buffPointer < DOWNLOADSIZE) {
    while (cli.available() && buffPointer < DOWNLOADSIZE) {
      char ch = (char) cli.read();
      if (!jsonStarted) {
        if (ch == '{') {
          jsonStarted = true;
        }
      }
      if (jsonStarted) {
        if (ch == '}') {
          charsSinceJsonEnd = 0;
        } else {
          charsSinceJsonEnd++;
        }
        response[buffPointer++] = ch;
      }
    }
    delay(1);
  }
  cli.stop();
  response[buffPointer - charsSinceJsonEnd] = '\0';  // OWM seems to send some weird extra characters we do not want

  if (!timeoutTimer) {
#ifdef DEBUG
    Serial.println("Timed out.");
#endif
    return "-1";
  }
  if (buffPointer == DOWNLOADSIZE) {
#ifdef DEBUG
    Serial.println("Maximum buffer size exceeded.");
#endif
    return "-1";
  }

#ifdef DEBUG
  Serial.println("'" + String(response) + "'");
#endif

  StaticJsonBuffer<JSONSIZE> json;
  JsonObject& root = json.parseObject(response);
  if (!root.success()) {
#ifdef DEBUG
    Serial.println("JSON invalid.");
#endif
    return "-1";
  }
  String strConditionId = root["list"][1]["weather"][0]["icon"].asString();
  if (!strConditionId.length()) {
    return "-1";
  }
#ifdef DEBUG
  Serial.println("Parsed JSON. Weather code: " + strConditionId);
#endif
  return strConditionId;  // 3 hour future weather by icon code
}