· 6 years ago · Nov 22, 2019, 10:32 AM
1 /*
2 * Author: Emmanuel Odunlade
3 * Complete Project Details https://randomnerdtutorials.com
4 */
5
6#include <ArduinoJson.h>
7#include <ESP8266WiFi.h>
8#include <WiFiClient.h>
9
10// Replace with your SSID and password details
11char ssid[] = "REPLACE_WITH_YOUR_SSID";
12char pass[] = "REPLACE_WITH_YOUR_PASSWORD";
13
14WiFiClient client;
15
16// Open Weather Map API server name
17const char server[] = "api.openweathermap.org";
18
19// Replace the next line to match your city and 2 letter country code
20String nameOfCity = "REPLACE_WITH_YOUR_CITY,REPLACE_WITH_YOUR_COUNTRY_CODE";
21// How your nameOfCity variable would look like for Lagos on Nigeria
22//String nameOfCity = "Lagos,NG";
23
24// Replace the next line with your API Key
25String apiKey = "REPLACE_WITH_YOUR_API_KEY";
26
27String text;
28
29int jsonend = 0;
30boolean startJson = false;
31int status = WL_IDLE_STATUS;
32
33int rainLed = 2; // Indicates rain
34int clearLed = 3; // Indicates clear sky or sunny
35int snowLed = 4; // Indicates snow
36int hailLed = 5; // Indicates hail
37
38#define JSON_BUFF_DIMENSION 2500
39
40unsigned long lastConnectionTime = 10 * 60 * 1000; // last time you connected to the server, in milliseconds
41const unsigned long postInterval = 10 * 60 * 1000; // posting interval of 10 minutes (10L * 1000L; 10 seconds delay for testing)
42
43void setup() {
44 pinMode(clearLed, OUTPUT);
45 pinMode(rainLed, OUTPUT);
46 pinMode(snowLed, OUTPUT);
47 pinMode(hailLed, OUTPUT);
48 Serial.begin(9600);
49
50 text.reserve(JSON_BUFF_DIMENSION);
51
52 WiFi.begin(ssid,pass);
53 Serial.println("connecting");
54 while (WiFi.status() != WL_CONNECTED) {
55 delay(500);
56 Serial.print(".");
57 }
58 Serial.println("WiFi Connected");
59 printWiFiStatus();
60}
61
62void loop() {
63 //OWM requires 10mins between request intervals
64 //check if 10mins has passed then conect again and pull
65 if (millis() - lastConnectionTime > postInterval) {
66 // note the time that the connection was made:
67 lastConnectionTime = millis();
68 makehttpRequest();
69 }
70}
71
72// print Wifi status
73void printWiFiStatus() {
74 // print the SSID of the network you're attached to:
75 Serial.print("SSID: ");
76 Serial.println(WiFi.SSID());
77
78 // print your WiFi shield's IP address:
79 IPAddress ip = WiFi.localIP();
80 Serial.print("IP Address: ");
81 Serial.println(ip);
82
83 // print the received signal strength:
84 long rssi = WiFi.RSSI();
85 Serial.print("signal strength (RSSI):");
86 Serial.print(rssi);
87 Serial.println(" dBm");
88}
89
90// to request data from OWM
91void makehttpRequest() {
92 // close any connection before send a new request to allow client make connection to server
93 client.stop();
94
95 // if there's a successful connection:
96 if (client.connect(server, 80)) {
97 // Serial.println("connecting...");
98 // send the HTTP PUT request:
99 client.println("GET /data/2.5/forecast?q=" + nameOfCity + "&APPID=" + apiKey + "&mode=json&units=metric&cnt=2 HTTP/1.1");
100 client.println("Host: api.openweathermap.org");
101 client.println("User-Agent: ArduinoWiFi/1.1");
102 client.println("Connection: close");
103 client.println();
104
105 unsigned long timeout = millis();
106 while (client.available() == 0) {
107 if (millis() - timeout > 5000) {
108 Serial.println(">>> Client Timeout !");
109 client.stop();
110 return;
111 }
112 }
113
114 char c = 0;
115 while (client.available()) {
116 c = client.read();
117 // since json contains equal number of open and close curly brackets, this means we can determine when a json is completely received by counting
118 // the open and close occurences,
119 //Serial.print(c);
120 if (c == '{') {
121 startJson = true; // set startJson true to indicate json message has started
122 jsonend++;
123 }
124 if (c == '}') {
125 jsonend--;
126 }
127 if (startJson == true) {
128 text += c;
129 }
130 // if jsonend = 0 then we have have received equal number of curly braces
131 if (jsonend == 0 && startJson == true) {
132 parseJson(text.c_str()); // parse c string text in parseJson function
133 text = ""; // clear text string for the next time
134 startJson = false; // set startJson to false to indicate that a new message has not yet started
135 }
136 }
137 }
138 else {
139 // if no connction was made:
140 Serial.println("connection failed");
141 return;
142 }
143}
144
145//to parse json data recieved from OWM
146void parseJson(const char * jsonString) {
147 //StaticJsonBuffer<4000> jsonBuffer;
148 const size_t bufferSize = 2*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(2) + 4*JSON_OBJECT_SIZE(1) + 3*JSON_OBJECT_SIZE(2) + 3*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + 2*JSON_OBJECT_SIZE(7) + 2*JSON_OBJECT_SIZE(8) + 720;
149 DynamicJsonBuffer jsonBuffer(bufferSize);
150
151 // FIND FIELDS IN JSON TREE
152 JsonObject& root = jsonBuffer.parseObject(jsonString);
153 if (!root.success()) {
154 Serial.println("parseObject() failed");
155 return;
156 }
157
158 JsonArray& list = root["list"];
159 JsonObject& nowT = list[0];
160 JsonObject& later = list[1];
161
162 // including temperature and humidity for those who may wish to hack it in
163
164 String city = root["city"]["name"];
165
166 float tempNow = nowT["main"]["temp"];
167 float humidityNow = nowT["main"]["humidity"];
168 String weatherNow = nowT["weather"][0]["description"];
169
170 float tempLater = later["main"]["temp"];
171 float humidityLater = later["main"]["humidity"];
172 String weatherLater = later["weather"][0]["description"];
173
174 // checking for four main weather possibilities
175 diffDataAction(weatherNow, weatherLater, "clear");
176 diffDataAction(weatherNow, weatherLater, "rain");
177 diffDataAction(weatherNow, weatherLater, "snow");
178 diffDataAction(weatherNow, weatherLater, "hail");
179
180 Serial.println();
181}
182
183//representing the data
184void diffDataAction(String nowT, String later, String weatherType) {
185 int indexNow = nowT.indexOf(weatherType);
186 int indexLater = later.indexOf(weatherType);
187 // if weather type = rain, if the current weather does not contain the weather type and the later message does, send notification
188 if (weatherType == "rain") {
189 if (indexNow == -1 && indexLater != -1) {
190 digitalWrite(rainLed,HIGH);
191 digitalWrite(clearLed,LOW);
192 digitalWrite(snowLed,LOW);
193 digitalWrite(hailLed,LOW);
194 Serial.println("Oh no! It is going to " + weatherType + " later! Predicted " + later);
195 }
196 }
197 // for snow
198 else if (weatherType == "snow") {
199 if (indexNow == -1 && indexLater != -1) {
200 digitalWrite(snowLed,HIGH);
201 digitalWrite(clearLed,LOW);
202 digitalWrite(rainLed,LOW);
203 digitalWrite(hailLed,LOW);
204 Serial.println("Oh no! It is going to " + weatherType + " later! Predicted " + later);
205 }
206
207 }
208 // can't remember last time I saw hail anywhere but just in case
209 else if (weatherType == "hail") {
210 if (indexNow == -1 && indexLater != -1) {
211 digitalWrite(hailLed,HIGH);
212 digitalWrite(clearLed,LOW);
213 digitalWrite(rainLed,LOW);
214 digitalWrite(snowLed,LOW);
215 Serial.println("Oh no! It is going to " + weatherType + " later! Predicted " + later);
216 }
217
218 }
219 // for clear sky, if the current weather does not contain the word clear and the later message does, send notification that it will be sunny later
220 else {
221 if (indexNow == -1 && indexLater != -1) {
222 Serial.println("It is going to be sunny later! Predicted " + later);
223 digitalWrite(clearLed,HIGH);
224 digitalWrite(rainLed,LOW);
225 digitalWrite(snowLed,LOW);
226 digitalWrite(hailLed,LOW);
227 }
228 }
229}