A class to gather weather data from an NWS server.
NWSWeather.h
- Committer:
- WiredHome
- Date:
- 2019-02-23
- Revision:
- 20:29257dc4c7aa
- Parent:
- 18:699590fd8856
File content as of revision 20:29257dc4c7aa:
/// @file NWSWeather.h /// This file contains the interface for gathering forecast from NWS. /// /// @attention This program is copyright (c) 2014 - 2019 by Smartware Computing, all /// rights reserved. /// /// This software, and/or material is the property of Smartware Computing. All /// use, disclosure, and/or reproduction not specifically authorized by Smartware /// Computing is prohibited. /// /// This software may be freely used for non-commercial purposes, and any /// derivative work shall carry the original copyright. The author of /// a derivative work shall make clear that it is a derivative work. /// /// @author David Smart, Smartware Computing /// #ifndef NWSWEATHER_H #define NWSWEATHER_H #include "mbed.h" #include "HTTPClient.h" // Set one of these to a 1, depending on your data source. #define WEATHER_GOV 0 // www.weather.gov (which went from http to https Jan 2019 #define OPEN_WEATHER 1 // openweathermap.org (which so far remains http) #if WEATHER_GOV == 1 static const char DEF_URL[] = "http://www.weather.gov/data/current_obs/"; #elif OPEN_WEATHER == 1 static const char DEF_URL[] = "http://api.openweathermap.org/data/2.5/weather?mode=xml&units=imperial&"; #endif /// Weather Service /// /// This class will fetch and parse weather data from an XML feed /// using a URL such as /// + https://www.weather.gov/data/current_obs/KALO.xml /// + http://api.openweathermap.org/data/2.5/weather?mode=xml&units=imperial&id=<Loc_ID>&APPID=<User_ID> /// /// @attention Proper use of this should follow the guideline, /// which is to not request this data from the server more often than /// necessary, and if available to recognize and use the suggested_pickup /// parameter for subsequent updates of the weather information. This /// class does not monitor the RTC so is unaware of the time of day. It /// is therefore up to the user to manage this recommended practice. /// /// Only the essential parameters are gathered, which is generally those /// from which you can derive others. It turns out this is also most of the /// parameters. /// /// From weather.gov /// \li observation_time_rfc822 - "Sun, 16 Mar 2014 09:54:00 -0500" /// \li suggested_pickup - "15 minutes after the hour" /// \li suggested_pickup_period - 60 (minutes) /// \li location /// \li weather /// \li temp_f /// \li temp_c /// \li relative_humidity /// \li wind_degrees /// \li wind_mph /// \li pressure_mb /// \li pressure_in /// \li dewpoint_f /// \li dewpoint_c /// \li windchill_f /// \li windchill_c /// \li visibility_mi /// \li icon_url_base - http://forecast.weather.gov/images/wtf/small/ /// \li icon_url_name - ovc.png (changes based on forecast) /// \li latitude /// \li longitude /// /// From openweathermap.org /// \li <current> /// \li <city id="4880889" name="Waterloo"> /// \li <coord lat="42.49" lon="-92.34"/> /// \li <country>US</country> /// \li <sun set="2019-01-08T22:54:13" rise="2019-01-08T13:38:34"/> /// \li </city> /// \li <temperature unit="fahrenheit" max="36.68" min="33.26" value="34.92"/> /// \li <humidity unit="%" value="93"/> /// \li <pressure unit="hPa" value="1009"/> /// \li <wind> /// \li <speed name="Gale" value="18.34"/> /// \li <gusts value="10.8"/> /// \li <direction name="North-northeast" value="340" code="NNW"/> /// \li </wind> /// \li <clouds name="scattered clouds" value="40"/> /// \li <visibility value="16093"/> /// \li <precipitation mode="no"/> /// \li <weather value="scattered clouds" icon="03n" number="802"/> /// \li <lastupdate value="2019-01-08T12:15:00"/> /// \li </current> /// class NWSWeather { public: /// Return code interpretation. typedef enum { noerror, ///< no error, or parameter has been updated. nomemory, ///< insufficient memory to complete operation. noresponse, ///< no response from server. badparameter, ///< bad parameter to function (typically out of range value). noupdate, ///< no update available. noparamfound ///< no parameter found. } NWSReturnCode_T; /// Identifies the type of a parameter. typedef enum { isFloat, ///< this parameter is a floating point value. isInt, ///< this parameter is an integer. isString ///< this parameter is a string value. } TypeOf_T; /// The union of available types. typedef union { float fValue; ///< the floating point value int iValue; ///< the integer value char * sValue; ///< the string value } Value_T; /// The array that defines what XML information to extract. /// /// It will not honor heirarchical XML tagging, each parsed /// tag must be in the same text line. /// /// Given two types of XML structure: /// 1) <sunrise>6:45 am</sunrise> /// 2) <sun rise="6:45 am" set="4:52 pm"> /// /// The key-value pairs can be defines to support either: /// "sunrise", NULL, NWSWeather::isString /// "sun", "rise", NWSWeather::isString /// /// @code /// static NWSWeather::XMLItem_T WeatherData[] = { /// {"weather", "value", NWSWeather::isString}, //<weather number="802" value="scattered clouds" icon="03n"/> /// {"temperature", "value", NWSWeather::isFloat}, //<temperature value="27.3" min="21.2" max="32" unit="fahrenheit"/> /// {"sun", "rise", NWSWeather::isString}, /// {"sun", "set", NWSWeather::isString}, /// }; /// @endcode typedef struct { const char * key; ///< pointer to the XML key of interest const char * param; ///< pointer to the parameter, or NULL if the key defines it TypeOf_T typeis; ///< the type of data bool updated; Value_T value; } XMLItem_T; /// Constructor. /// /// Create the object to acquire the weather information from NOAA. /// The full form of a valid url to acquire the data from is: /// "http://www.weather.gov/data/current_obs/SITE.xml", where SITE /// is replaced by the proper site location code. /// /// location codes are available at http://weather.noaa.gov/data/nsd_bbsss.txt, /// and you can use the http://forecast.weather.gov/zipcity.php search tool /// to search based on either zip code or city, state. /// /// It is possible to construct the NWSWeather object with an alternate /// base url, but this is only useful if the alternate site is xml format /// compatible. /// /// /// @code /// NWSWeather wx; /// #if WEATHER_GOV == 1 /// wx.get("KALO"}; /// #elif OPEN_WEATHER == 1 /// wx.get(4880889, "user_id"); /// #endif /// wx.PrintAllWeatherRecords(); /// @endcode /// /// @code /// NWSWeather wx("http://some.alternate.site/path/"); /// wx.get("KALO"}; /// wx.PrintAllWeatherRecords(); /// @endcode /// /// @param[in] baseurl is an optional parameter to set the base url. If this /// is not set a default is used. /// If it is set, that alternate base url is used. /// #ifdef WEATHER_GOV /// http://www.weather.gov/data/current_obs/ /// appended are two parameters /// <loc_code> /// ".xml" /// #elif OPEN_WEATHER == 1 /// http://api.openweathermap.org/data/2.5/weather?mode=xml&units=imperial /// appended are two parameters /// &id=<loc_code> /// &APPID=<user_id> /// #endif /// for future forecast /// http://forecast.weather.gov/MapClick.php?lat=42.47508&lon=-92.36704926700929 // &unit=0&lg=english&FcstType=dwml /// NWSWeather(XMLItem_T * pList, int count); /// Destructor. ~NWSWeather(); /// set an alternate base url after construction of the NWSWeather object. /// /// @param[in] alternateurl is the new url to replace the baseurl. /// @returns success/failure code. @see NWSReturnCode_T. /// NWSReturnCode_T setAlternateURL(const char * alternateurl); #if WEATHER_GOV == 1 /// get the current conditions weather data from the specified site. /// /// This does the work to fetch the weather data from weatherdata.gov, /// for the site of interest. /// /// @param[in] site is the site/location code of the site of interest. /// @param[in] responseSize is optional but important. It defaults to 2500 /// and is intended to tell this method the size of a buffer it /// should temporarily allocate to receive and process the data. /// @returns success/failure code. @see NWSReturnCode_T. /// NWSReturnCode_T get(const char * site, int responseSize = 2500); #elif OPEN_WEATHER == 1 /// get the current conditions weather data from the specified site. /// /// This does the work to fetch the weather data from openweathermap.org, /// for the site of interest. /// /// @param[in] site is the site/location code string of the site of interest. /// @param[in] userid is the code string registered with the site to access the data. /// @param[in] responseSize is optional but important. It defaults to 2500 /// and is intended to tell this method the size of a buffer it /// should temporarily allocate to receive and process the data. /// @returns success/failure code. @see NWSReturnCode_T. /// NWSReturnCode_T get(const char * site, const char * userid, int responseSize = 1000); #endif /// get the count of the number of weather parameters. /// /// @returns the count of the number of parameters for which /// data is expected. uint16_t count(void); /// determines if a specific parameter was updated from the last /// acquisition. /// /// @param[in] i is the item of interest. /// @returns noerror if the parameter is up to date. @see NWSReturnCode_T. /// NWSReturnCode_T isUpdated(uint16_t i); /// determines if a specific parameter was updated from the last /// acquisition. /// /// @param[in] name is the item of interest. /// @returns noerror if the parameter is up to date. @see NWSReturnCode_T. /// NWSReturnCode_T isUpdated(const char * name); /// get one of the weather parameters. /// /// This fetches one of the available weather parameters by setting /// user supplied pointers to reference the parameter. /// /// @code /// // Iterate over each of the parameters /// for (i=0; i<wx.count(); i++) { /// char * name; TypeOf_T type; char * value; /// if (wx.getParam(i, name, &type, value)) { /// // print the values /// } /// } /// @endcode /// /// @code /// // Get the names of the available parameters. /// for (i=0; i<wx.count(); i++) { /// char *name; /// if (wx.getParam(i, name) == noerror) { /// // print the names of the parameters /// } /// } /// @endcode /// /// @param[in] i is index of the parameter of interest. /// @param[in] name is a pointer that is set to point to the name of parameter i. /// @param[out] value is an optional pointer that is then set to point to the value of parameter i. /// @param[out] typeis is an optional pointer that is set to indicate the type of the value. /// @returns success/failure code. @see NWSReturnCode_T. /// NWSReturnCode_T getParam(uint16_t i, char *name, Value_T *value = NULL, TypeOf_T *typeis = NULL); /// get one of the weather parameters. /// /// This searchs the parameter set for the named parameter, and if found /// it will set the user supplied pointers to the value and type information /// for that parameter. /// /// @code /// char sunrise[30]; TypeOf_T type; /// if (wx.getParam("sun", "rise", &sunrise, &type) == noerror) { /// // print the values /// } /// @endcode /// /// @param[in] name is a const pointer to a string naming the parameter of interest. /// @param[in] param is the secondary part of the parameter. /// @param[out] value is a pointer that is set to point to the value of parameter i. /// @param[out] typeis is a pointer that is set to indicate the type of the value. /// @returns success/failure code. @see NWSReturnCode_T. /// NWSReturnCode_T getParam(const char *name, const char * param, Value_T *value, TypeOf_T *typeis = NULL); /// get one of the weather parameters. /// /// This searchs the parameter set for the named parameter, and if found /// it will set the user supplied pointers to the value and type information /// for that parameter. /// /// @code /// float value; TypeOf_T type; /// if (wx.getParam("temp_f", &value, &type) == noerror) { /// // print the values /// } /// @endcode /// /// @param[in] name is a const pointer to a string naming the parameter of interest. /// @param[out] value is a pointer that is set to point to the value of parameter i. /// @param[out] typeis is a pointer that is set to indicate the type of the value. /// @returns success/failure code. @see NWSReturnCode_T. /// NWSReturnCode_T getParam(const char *name, Value_T *value, TypeOf_T *typeis = NULL); /// Print to stdout the specified weather record. /// /// Prints the specified record as a "Parmeter = value\r\n" string, formatted /// so that subsequent prints line up at the '=' sign. /// /// @param[in] i specifies the record. /// void PrintWeatherRecord(uint16_t i); /// Print all the records to stdout. /// /// calls PrintWeatherRecord for each available parameter. /// void PrintAllWeatherRecords(void); /// Clear all the data and free allocated memory. /// void ClearWeatherRecords(void); private: char * m_baseurl; NWSReturnCode_T ParseWeatherRecord(char * p); NWSReturnCode_T ExtractParam(int i, char * pValue, char * pEnd); void ParseWeatherXML(char * message); XMLItem_T * WeatherData; int WeatherItemCount; }; #endif // NWSWEATHER_H