void readWeather() { byte Attempts = 1; bool RxWeather = false; bool RxForecast = false; WiFiClient client; // wifi client object while ((RxWeather == false || RxForecast == false) && Attempts <= 2) { // Try up-to 2 time for Weather and Forecast data if (RxWeather == false) RxWeather = obtainWeatherData(client, "weather"); if (RxForecast == false) RxForecast = obtainWeatherData(client, "forecast"); Attempts++; } Serial.println("Received all weather data..."); } //######################################################################################### bool obtainWeatherData(WiFiClient & client, const String & RequestType) { const String units = (Units == "M" ? "metric" : "imperial"); client.stop(); // close connection before sending a new request HTTPClient http; // String uri = "/data/2.5/" + RequestType + "/daily?q=" + City + "," + Country + "&APPID=" + apikey + "&mode=json&units=" + units + "&lang=" + Language; String uri = "/data/2.5/" + RequestType + "?q=" + City + "," + Country + "&APPID=" + apikey + "&mode=json&units=" + units + "&lang=" + Language; if (RequestType != "weather") { if(forcast==0) { uri = "/data/2.5/" + RequestType + "/daily?q=" + City + "," + Country + "&APPID=" + apikey + "&mode=json&units=" + units + "&lang=" + Language; uri += "&cnt=" + String(max_readings); } else { uri = "/data/2.5/" + RequestType + "?q=" + City + "," + Country + "&APPID=" + apikey + "&mode=json&units=" + units; uri += "&cnt=" + String(max_readings1); // data/2.5/forecast?q=Yevpatoriya,UA&APPID=a0b9f94d153cbcbfeb00ea5632db24ac&mode=json&units=metric&cnt=24 } } Serial.println(uri); http.begin(client, server, 80, uri); //http.begin(uri,test_root_ca); //HTTPS example connection int httpCode = http.GET(); if (httpCode == HTTP_CODE_OK) { // Serial.println("HTTP_CODE_OK"); if (!DecodeWeather(http.getStream(), RequestType)) return false; client.stop(); http.end(); return true; } else { Serial.printf("connection failed, error: %s", http.errorToString(httpCode).c_str()); Serial.println(" "); client.stop(); http.end(); return false; } http.end(); return true; } //************************************************************************************************************ bool DecodeWeather(WiFiClient& json, String Type) { Serial.print(F("\nCreating object...and ")); DynamicJsonDocument doc(64 * 1024); // allocate the JsonDocument DeserializationError error = deserializeJson(doc, json); // Deserialize the JSON document if (error) { // Test if parsing succeeds. Serial.print(F("deserializeJson() failed: ")); Serial.println(error.c_str()); return false; } // convert it to a JsonObject JsonObject root = doc.as(); Serial.println(" Decoding " + Type + " data"); if (Type == "weather") { // All Serial.println statements are for diagnostic purposes and some are not required, remove if not needed with // //WxConditions[0].lon = root["coord"]["lon"].as(); Serial.println(" Lon: " + String(WxConditions[0].lon)); //WxConditions[0].lat = root["coord"]["lat"].as(); Serial.println(" Lat: " + String(WxConditions[0].lat)); WxConditions[0].Main0 = root["weather"][0]["main"].as(); Serial.println("Main: " + String(WxConditions[0].Main0)); WxConditions[0].Forecast0 = root["weather"][0]["description"].as(); Serial.println("For0: " + String(WxConditions[0].Forecast0)); //WxConditions[0].Forecast1 = root["weather"][1]["description"].as(); Serial.println("For1: " + String(WxConditions[0].Forecast1)); //WxConditions[0].Forecast2 = root["weather"][2]["description"].as(); Serial.println("For2: " + String(WxConditions[0].Forecast2)); WxConditions[0].Icon = root["weather"][0]["icon"].as(); Serial.println("Icon: " + String(WxConditions[0].Icon)); WxConditions[0].Temperature = root["main"]["temp"].as(); Serial.println("Temp: " + String(WxConditions[0].Temperature)); WxConditions[0].Pressure = root["main"]["pressure"].as(); Serial.println("Pres: " + String(WxConditions[0].Pressure)); WxConditions[0].Humidity = root["main"]["humidity"].as(); Serial.println("Humi: " + String(WxConditions[0].Humidity)); WxConditions[0].Low = root["main"]["temp_min"].as(); Serial.println("TLow: " + String(WxConditions[0].Low)); WxConditions[0].High = root["main"]["temp_max"].as(); Serial.println("THig: " + String(WxConditions[0].High)); WxConditions[0].Windspeed = root["wind"]["speed"].as(); Serial.println("WSpd: " + String(WxConditions[0].Windspeed)); WxConditions[0].Winddir = root["wind"]["deg"].as(); Serial.println("WDir: " + String(WxConditions[0].Winddir)); WxConditions[0].Cloudcover = root["clouds"]["all"].as(); Serial.println("CCov: " + String(WxConditions[0].Cloudcover)); // in % of cloud cover WxConditions[0].Visibility = root["visibility"].as(); Serial.println("Visi: " + String(WxConditions[0].Visibility)); // in metres WxConditions[0].Rainfall = root["rain"]["1h"].as(); Serial.println("Rain: " + String(WxConditions[0].Rainfall)); WxConditions[0].Snowfall = root["snow"]["1h"].as(); Serial.println("Snow: " + String(WxConditions[0].Snowfall)); //WxConditions[0].Country = root["sys"]["country"].as(); Serial.println("Ctry: " + String(WxConditions[0].Country)); WxConditions[0].Sunrise = root["sys"]["sunrise"].as(); Serial.println("SRis: " + String(WxConditions[0].Sunrise)); WxConditions[0].Sunset = root["sys"]["sunset"].as(); Serial.println("SSet: " + String(WxConditions[0].Sunset)); WxConditions[0].Timezone = root["timezone"].as(); Serial.println("TZon: " + String(WxConditions[0].Timezone)); } if (Type == "forecast") { //Serial.println(json); if(forcast==0) { Serial.print(F("\nReceiving Forecast period - ")); //------------------------------------------------ JsonArray list = root["list"]; for (byte r = 0; r < max_readings; r++) { Serial.println("\nPeriod-" + String(r) + "--------------"); WxForecast[r].Dt = list[r]["dt"].as(); // WxForecast[r].Temperature = list[r]["main"]["temp"].as(); Serial.println("Temp: " + String(WxForecast[r].Temperature)); WxForecast[r].day = list[r]["temp"]["day"].as(); Serial.println("Tday: " + String(WxForecast[r].day)); WxForecast[r].night = list[r]["temp"]["night"].as(); Serial.println("Tnight: " + String(WxForecast[r].night)); WxForecast[r].Pressure = list[r]["pressure"].as(); Serial.println("Pres: " + String(WxForecast[r].Pressure)); WxForecast[r].Humidity = list[r]["humidity"].as(); Serial.println("Humi: " + String(WxForecast[r].Humidity)); //WxForecast[r].Forecast0 = list[r]["weather"][0]["main"].as(); Serial.println("For0: " + String(WxForecast[r].Forecast0)); //WxForecast[r].Forecast1 = list[r]["weather"][1]["main"].as(); Serial.println("For1: " + String(WxForecast[r].Forecast1)); //WxForecast[r].Forecast2 = list[r]["weather"][2]["main"].as(); Serial.println("For2: " + String(WxForecast[r].Forecast2)); WxForecast[r].Icon = list[r]["weather"][0]["icon"].as(); Serial.println("Icon: " + String(WxForecast[r].Icon)); //WxForecast[r].Description = list[r]["weather"][0]["description"].as(); Serial.println("Desc: " + String(WxForecast[r].Description)); WxForecast[r].Cloudcover = list[r]["clouds"].as(); Serial.println("CCov: " + String(WxForecast[r].Cloudcover)); // in % of cloud cover WxForecast[r].Windspeed = list[r]["speed"].as(); Serial.println("WSpd: " + String(WxForecast[r].Windspeed)); WxForecast[r].Winddir = list[r]["deg"].as(); Serial.println("WDir: " + String(WxForecast[r].Winddir)); // WxForecast[r].Rainfall = list[r]["rain"]["3h"].as(); Serial.println("Rain: " + String(WxForecast[r].Rainfall)); // WxForecast[r].Snowfall = list[r]["snow"]["3h"].as(); Serial.println("Snow: " + String(WxForecast[r].Snowfall)); // WxForecast[r].Period = list[r]["dt_txt"].as(); Serial.println("Peri: " + String(WxForecast[r].Period)); } //------------------------------------------ float pressure_trend = WxForecast[0].Pressure - WxForecast[2].Pressure; // Measure pressure slope between ~now and later pressure_trend = ((int)(pressure_trend * 10)) / 10.0; // Remove any small variations less than 0.1 WxConditions[0].Trend = "="; if (pressure_trend > 0) WxConditions[0].Trend = "+"; if (pressure_trend < 0) WxConditions[0].Trend = "-"; if (pressure_trend == 0) WxConditions[0].Trend = "0"; if (Units == "I") Convert_Readings_to_Imperial(); } else { //Serial.println(json); Serial.print(F("\nReceiving Forecast period - ")); //------------------------------------------------ JsonArray list = root["list"]; for (byte r = 0; r < max_readings1; r++) { Serial.println("\nPeriod-" + String(r) + "--------------"); WxForecast[r].Dt = list[r]["dt"].as(); WxForecast[r].Temperature = list[r]["main"]["temp"].as(); Serial.println("Temp: " + String(WxForecast[r].Temperature)); WxForecast[r].Low = list[r]["main"]["temp_min"].as(); Serial.println("TLow: " + String(WxForecast[r].Low)); WxForecast[r].High = list[r]["main"]["temp_max"].as(); Serial.println("THig: " + String(WxForecast[r].High)); WxForecast[r].Pressure = list[r]["main"]["pressure"].as(); Serial.println("Pres: " + String(WxForecast[r].Pressure)); WxForecast[r].Humidity = list[r]["main"]["humidity"].as(); Serial.println("Humi: " + String(WxForecast[r].Humidity)); //WxForecast[r].Forecast0 = list[r]["weather"][0]["main"].as(); Serial.println("For0: " + String(WxForecast[r].Forecast0)); //WxForecast[r].Forecast1 = list[r]["weather"][1]["main"].as(); Serial.println("For1: " + String(WxForecast[r].Forecast1)); //WxForecast[r].Forecast2 = list[r]["weather"][2]["main"].as(); Serial.println("For2: " + String(WxForecast[r].Forecast2)); WxForecast[r].Icon = list[r]["weather"][0]["icon"].as(); Serial.println("Icon: " + String(WxForecast[r].Icon)); //WxForecast[r].Description = list[r]["weather"][0]["description"].as(); Serial.println("Desc: " + String(WxForecast[r].Description)); //WxForecast[r].Cloudcover = list[r]["clouds"]["all"].as(); Serial.println("CCov: " + String(WxForecast[r].Cloudcover)); // in % of cloud cover //WxForecast[r].Windspeed = list[r]["wind"]["speed"].as(); Serial.println("WSpd: " + String(WxForecast[r].Windspeed)); //WxForecast[r].Winddir = list[r]["wind"]["deg"].as(); Serial.println("WDir: " + String(WxForecast[r].Winddir)); WxForecast[r].Rainfall = list[r]["rain"]["3h"].as(); Serial.println("Rain: " + String(WxForecast[r].Rainfall)); WxForecast[r].Snowfall = list[r]["snow"]["3h"].as(); Serial.println("Snow: " + String(WxForecast[r].Snowfall)); WxForecast[r].Period = list[r]["dt_txt"].as(); Serial.println("Peri: " + String(WxForecast[r].Period)); } //------------------------------------------ float pressure_trend = WxForecast[0].Pressure - WxForecast[2].Pressure; // Measure pressure slope between ~now and later pressure_trend = ((int)(pressure_trend * 10)) / 10.0; // Remove any small variations less than 0.1 WxConditions[0].Trend = "="; if (pressure_trend > 0) WxConditions[0].Trend = "+"; if (pressure_trend < 0) WxConditions[0].Trend = "-"; if (pressure_trend == 0) WxConditions[0].Trend = "0"; if (Units == "I") Convert_Readings_to_Imperial(); } } return true; } //######################################################################################### void Convert_Readings_to_Imperial() { // Only the first 3-hours are used WxConditions[0].Pressure = hPa_to_inHg(WxConditions[0].Pressure); WxForecast[0].Rainfall = mm_to_inches(WxForecast[0].Rainfall); WxForecast[0].Snowfall = mm_to_inches(WxForecast[0].Snowfall); } //************************************************************************************ //************************************************************************************************************ float mm_to_inches(float value_mm) { return 0.0393701 * value_mm; } float hPa_to_inHg(float value_hPa) { return 0.02953 * value_hPa; }