Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
NWSWeather.cpp
- Committer:
- WiredHome
- Date:
- 2016-01-26
- Revision:
- 14:bcc80874e824
- Parent:
- 13:a9ac9dde4f7f
- Child:
- 15:c353545f9f13
File content as of revision 14:bcc80874e824:
// // This file contains the interface for gathering forecast from NWS. // // attention: This program is copyright (c) 2014 - 2015 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 // #include "NWSWeather.h" #include "Utility.h" // private memory manager #ifndef UTILITY_H #define swMalloc malloc // use the standard #define swFree free #endif #define DEBUG "NWS " // ... // INFO("Stuff to show %d", var); // new-line is automatically appended // #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) #define INFO(x, ...) std::printf("[INF %s %3d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__); #define WARN(x, ...) std::printf("[WRN %s %3d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__); #define ERR(x, ...) std::printf("[ERR %s %3d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__); #else #define INFO(x, ...) #define WARN(x, ...) #define ERR(x, ...) #endif // 20151126 - Not sure when, but the NWS site stopped accepting requests unless a // User-Agent was provided. It doesn't seem to matter the contents of // the U-A string. static const char * hdrs[] = { "Connection", "keep-alive", "Accept", "text/html", "User-Agent", "SW_Client" }; #define HDR_PAIRS 3 static NWSWeather::XMLItem_T WeatherData[] = { {"observation_time_rfc822", NWSWeather::isString}, {"suggested_pickup", NWSWeather::isInt}, {"suggested_pickup_period", NWSWeather::isInt}, {"location", NWSWeather::isString}, {"weather", NWSWeather::isString}, {"temp_f", NWSWeather::isFloat}, {"temp_c", NWSWeather::isFloat}, {"relative_humidity", NWSWeather::isInt}, {"wind_degrees", NWSWeather::isInt}, {"wind_mph", NWSWeather::isFloat}, {"pressure_mb", NWSWeather::isFloat}, {"pressure_in", NWSWeather::isFloat}, {"dewpoint_f", NWSWeather::isFloat}, {"dewpoint_c", NWSWeather::isFloat}, {"windchill_f", NWSWeather::isFloat}, {"windchill_c", NWSWeather::isFloat}, {"visibility_mi", NWSWeather::isFloat}, {"icon_url_base", NWSWeather::isString}, {"icon_url_name", NWSWeather::isString}, {"latitude", NWSWeather::isFloat}, {"longitude", NWSWeather::isFloat}, }; #define MAXPARAMLEN 23 #define WeatherItemCount (sizeof(WeatherData)/sizeof(WeatherData[0])) NWSWeather::NWSWeather(const char * baseURL) : m_baseurl(0) { setAlternateURL(baseURL); } NWSWeather::~NWSWeather() { ClearWeatherRecords(); } NWSWeather::NWSReturnCode_T NWSWeather::setAlternateURL(const char * baseURL) { int n = strlen(baseURL)+1; if (m_baseurl) swFree(m_baseurl); m_baseurl = (char *)swMalloc(n); if (m_baseurl) strncpy(m_baseurl, baseURL, n); else { ERR("failed to swMalloc(%d)", n); return nomemory; } ClearWeatherRecords(); return noerror; } uint16_t NWSWeather::count(void) { return WeatherItemCount; } NWSWeather::NWSReturnCode_T NWSWeather::get(const char * site, int responseSize) { HTTPClient http; NWSReturnCode_T retCode = nomemory; char *url = NULL; char *message = (char *)swMalloc(responseSize); INFO("get(%s)", site); if (!message) ERR("failed to swMalloc(%d)", responseSize); while (message) { int n = strlen(m_baseurl) + strlen(site) + 5; url = (char *)swMalloc(n); if (url) { strcpy(url, m_baseurl); strcat(url, site); strcat(url, ".xml"); INFO(" url: %s", url); http.setMaxRedirections(3); http.customHeaders(hdrs, HDR_PAIRS); int ret = http.get(url, message, responseSize); if (!ret) { INFO("ret is %d", ret); if (http.getHTTPResponseCode() >= 300 && http.getHTTPResponseCode() < 400) { INFO(" http.getHTTPResponseCode(): %d", http.getHTTPResponseCode()); retCode = noerror; // redirection that was not satisfied. break; } else { INFO("wx get %d bytes.\r\n", strlen(message)); ParseWeatherXML(message); INFO("wx parse complete.\r\n"); retCode = noerror; break; } } else { WARN("get returned %d, no response?", ret); retCode = noresponse; break; } } else { ERR("failed to swMalloc(%d)", n); retCode = nomemory; break; } } // while(...) but configured with break for only 1 pass. INFO(" ret is %d", retCode); if (url) swFree(url); if (message) swFree(message); INFO(" mem freed."); return retCode; } NWSWeather::NWSReturnCode_T NWSWeather::isUpdated(uint16_t i) { if (i < WeatherItemCount) { if (WeatherData[i].updated) return noerror; else return noupdate; } else { return badparameter; } } NWSWeather::NWSReturnCode_T NWSWeather::isUpdated(const char * name) { if (name) { for (int i=0; i < WeatherItemCount; i++) { if (strcmp(name, WeatherData[i].name) == 0) { if (WeatherData[i].updated) return noerror; else return noupdate; } } } return badparameter; } NWSWeather::NWSReturnCode_T NWSWeather::getParam(uint16_t i, char *name, Value_T *value, TypeOf_T *typeis) { if (i < WeatherItemCount) { *name = *WeatherData[i].name; *value = WeatherData[i].value; if (typeis) *typeis = WeatherData[i].typeis; return noerror; } else { return badparameter; } } NWSWeather::NWSReturnCode_T NWSWeather::getParam(const char *name, Value_T *value, TypeOf_T *typeis) { for (int i=0; i < WeatherItemCount; i++) { if (strcmp(name, WeatherData[i].name) == 0) { *value = WeatherData[i].value; if (typeis) *typeis = WeatherData[i].typeis; return noerror; } } return badparameter; } void NWSWeather::ClearWeatherRecords(void) { int i; int count = WeatherItemCount; for (i=0; i<count; i++) { switch(WeatherData[i].typeis) { case isFloat: WeatherData[i].value.fValue = 0.0; WeatherData[i].updated = false; break; case isInt: WeatherData[i].value.iValue = 0; WeatherData[i].updated = false; break; case isString: if (WeatherData[i].value.sValue) { swFree(WeatherData[i].value.sValue); WeatherData[i].value.sValue = NULL; } WeatherData[i].updated = false; break; default: break; } } } void NWSWeather::PrintWeatherRecord(uint16_t i) { if (i < WeatherItemCount) { switch(WeatherData[i].typeis) { case isFloat: printf("%23s = %f\r\n", WeatherData[i].name, WeatherData[i].value.fValue); break; case isInt: printf("%23s = %d\r\n", WeatherData[i].name, WeatherData[i].value.iValue); break; case isString: printf("%23s = %s\r\n", WeatherData[i].name, WeatherData[i].value.sValue); break; default: break; } } } void NWSWeather::PrintAllWeatherRecords(void) { for (int i=0; i<WeatherItemCount; i++) { PrintWeatherRecord(i); } } NWSWeather::NWSReturnCode_T NWSWeather::ParseWeatherRecord(char * p) { // <tag_name>value</tag_name> // p1 p2 p3 char *p1, *p2, *p3; int i; int n; int count = WeatherItemCount; INFO("ParseWeatherRecord(%s)", p); p1 = strchr(p, '<'); // Pattern Matching <key>value</key> if (p1++) { p2 = strchr(p1+1, '>'); if (p2) { p3 = strchr(p2+1, '<'); if (p3) { *p2++ = '\0'; *p3 = '\0'; for (i=0; i<count; i++) { if (strcmp(p1, WeatherData[i].name) == 0) { switch(WeatherData[i].typeis) { case isFloat: WeatherData[i].value.fValue = atof(p2); WeatherData[i].updated = true; break; case isInt: WeatherData[i].value.iValue = atoi(p2); WeatherData[i].updated = true; break; case isString: if (WeatherData[i].value.sValue) swFree(WeatherData[i].value.sValue); n = strlen(p2)+1; INFO(" pre- swMalloc(%d)", n); WeatherData[i].value.sValue = (char *)swMalloc(n); INFO(" post-swMalloc"); if (WeatherData[i].value.sValue) { strcpy(WeatherData[i].value.sValue, p2); WeatherData[i].updated = true; } else { ERR("failed to swMalloc(%d)", n); break; } break; default: ERR("unknown type"); return badparameter; //break; } //INFO("pw end"); return noerror; } } } } } //INFO("pw end"); return noparamfound; } void NWSWeather::ParseWeatherXML(char * message) { char * p = message; INFO("ParseWeatherXML: %s", p); ClearWeatherRecords(); INFO("cleared old"); while (*p) { char * n = strchr(p, '\n'); if (*n) { *n = '\0'; ParseWeatherRecord(p); p = n + 1; } else { ParseWeatherRecord(p); break; } } }