// -------- Functions -------- /// <summary> /// Queries the weather service in the background and returns /// what should be send over IRC. /// </summary> /// <param name="zip">Zip code.</param> /// <returns> /// The string that should go out over IRC. /// Can be report or an error message. /// </returns> public async Task <string> QueryWeather(string zip) { string returnString = string.Empty; try { if (reportCache.ContainsKey(zip)) { // If our cache reports a null, its an invalid zip code. Print error message. if (reportCache[zip] == null) { returnString = "Error with one or more zip codes: Error: Zip code \"" + zip + "\" is not a valid US zip code"; } // Otherwise, if the value in our cache is old, get updated info. else if ((DateTime.UtcNow - reportCache[zip].ConstructionTime).TotalSeconds >= this.weatherQuery.Cooldown) { // Get the weather report in the background. WeatherReport report = await this.weatherQuery.QueryForWeather(zip); returnString = report.ToString(); reportCache[zip] = report; } // Otherwise, our cache is still new, do not query NOAA, just return our cache. else { returnString = reportCache[zip].ToString(); } } else { // Get the weather report in the background. WeatherReport report = await this.weatherQuery.QueryForWeather(zip); returnString = report.ToString(); reportCache[zip] = report; } } catch (QueryException err) { // Only fill our cache if an invalid zip. Its possible we timed out // or the service is just having a tough time at the moment. We don't // want to fill the cache with a zip code that may be okay in the future, // just not now. if (err.ErrorCode == QueryErrors.InvalidZip) { reportCache[zip] = null; // Invalid zip, no sense wasting our time querying the SOAP service next time around. } returnString = err.Message; } catch (Exception err) { returnString = err.Message; } return(returnString); }
// -------- Functions -------- /// <summary> /// Queries NOAA in the backgroud. /// </summary> /// <param name="zip">The ZIP code to get weather information from.</param> /// <returns>The weather report from NOAA.</returns> public Task <WeatherReport> QueryForWeather(string zip) { return(Task.Run( delegate() { // First, get the Lat/Long of the zip code. Tuple <string, string> latLon; using (WebClient client = new WebClient()) { client.QueryString.Add("whichClient", "LatLonListZipCode"); client.QueryString.Add("listZipCodeList", zip); client.QueryString.Add("Submit", "Submit"); // Per http://stackoverflow.com/questions/32641072/current-observation-feed-from-weather-gov-forbidden-403, // Weather.gov now requires a user agent when querying their API. client.Headers.Add("user-agent", userAgent); string response = client.DownloadString("https://graphical.weather.gov/xml/SOAP_server/ndfdXMLclient.php"); latLon = XmlLoader.ParseLatitudeLongitude(response, zip); } // Next, get the weather report. WeatherReport report = null; using (WebClient client = new WebClient()) { client.QueryString.Add("whichClient", "GmlLatLonList"); client.QueryString.Add("gmlListLatLon", Uri.EscapeDataString(latLon.Item1 + "," + latLon.Item2)); client.QueryString.Add("featureType", "Forecast_Gml2Point"); client.QueryString.Add("product", "glance"); client.QueryString.Add("Unit", "e"); client.QueryString.Add("maxt", "maxt"); // High Temp client.QueryString.Add("mint", "mint"); // Low Temp client.QueryString.Add("pop12", "pop12"); // Precipitation chance client.QueryString.Add("wx", "wx"); // Current Conditations client.QueryString.Add("appt", "appt"); // Apparent Temp client.QueryString.Add("temp", "temp"); // Current Temp client.QueryString.Add("Submit", "Submit"); client.Headers.Add("user-agent", userAgent); string response = client.DownloadString("https://graphical.weather.gov/xml/SOAP_server/ndfdXMLclient.php"); report = XmlLoader.ParseWeatherReport(response, zip); } return report; } )); }
// -------- Functions -------- /// <summary> /// Queries NOAA in the backgroud. /// </summary> /// <param name="zip">The ZIP code to get weather information from.</param> /// <returns>The weather report from NOAA.</returns> public Task <WeatherReport> QueryForWeather(string zip) { return(Task.Run( delegate() { // First, get the Lat/Long of the zip code. Tuple <string, string> latLon; using (WebClient client = new WebClient()) { client.QueryString.Add("whichClient", "LatLonListZipCode"); client.QueryString.Add("listZipCodeList", zip); client.QueryString.Add("Submit", "Submit"); string response = client.DownloadString("http://graphical.weather.gov/xml/SOAP_server/ndfdXMLclient.php"); latLon = XmlLoader.ParseLatitudeLongitude(response, zip); } // Next, get the weather report. WeatherReport report = null; using (WebClient client = new WebClient()) { client.QueryString.Add("whichClient", "GmlLatLonList"); client.QueryString.Add("gmlListLatLon", Uri.EscapeDataString(latLon.Item1 + "," + latLon.Item2)); client.QueryString.Add("featureType", "Forecast_Gml2Point"); client.QueryString.Add("product", "glance"); client.QueryString.Add("Unit", "e"); client.QueryString.Add("maxt", "maxt"); // High Temp client.QueryString.Add("mint", "mint"); // Low Temp client.QueryString.Add("pop12", "pop12"); // Precipitation chance client.QueryString.Add("wx", "wx"); // Current Conditations client.QueryString.Add("appt", "appt"); // Apparent Temp client.QueryString.Add("temp", "temp"); // Current Temp client.QueryString.Add("Submit", "Submit"); string response = client.DownloadString("http://graphical.weather.gov/xml/SOAP_server/ndfdXMLclient.php"); report = XmlLoader.ParseWeatherReport(response, zip); } return report; } )); }
/// <summary> /// Parses the given XML from NOAA to a WeatherReport our plugin can use. /// </summary> /// <exception cref="ApplicationException">XML from NOAA is invalid.</exception> /// <param name="noaaXml">The XML from NOAA's SOAP service.</param> /// <param name="zipCode">The zip code we are getting the information from.</param> /// <returns>A Weather Report object.</returns> public static WeatherReport ParseWeatherReport(string noaaXml, string zipCode) { XmlDocument doc = new XmlDocument(); doc.LoadXml(noaaXml); XmlNodeList forecastNodes = doc.GetElementsByTagName("app:Forecast_Gml2Point"); if (forecastNodes.Count == 0) { CheckForErrorResponse(noaaXml); throw new QueryException( QueryErrors.MissingForecast, "Got invalid XML from NOAA. Could not get weather report from zip code " + zipCode ); } WeatherReport report = new WeatherReport(); report.ZipCode = zipCode; XmlNode forecastNode = forecastNodes[0]; foreach (XmlNode childNode in forecastNode.ChildNodes) { switch (childNode.Name) { // High Temperature: case "app:maximumTemperature": report.HighTemp = childNode.InnerText; break; // Low Temperature: case "app:minimumTemperature": report.LowTemp = childNode.InnerText; break; // Current Temperature: case "app:temperature": report.CurrentTemp = childNode.InnerText; break; // Apparent Temperature: case "app:apparentTemperature": report.ApparentTemp = childNode.InnerText; break; // Chance of Precipitation: case "app:probOfPrecip12hourly": report.ChanceOfPrecipitation = childNode.InnerText; break; // Current Conditions: case "app:weatherPhrase": report.CurrentConditions = childNode.InnerText; break; } } return(report); }