David Smart / NWSWeather
Committer:
WiredHome
Date:
Thu Aug 06 11:12:15 2015 +0000
Revision:
11:98afc5abbfb8
Parent:
10:548533964124
Child:
12:d70de07ca914
Code changes based on running through a stricter compiler.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 2:eae60b64066e 1 //
WiredHome 2:eae60b64066e 2 // This file contains the interface for gathering forecast from NWS.
WiredHome 2:eae60b64066e 3 //
WiredHome 2:eae60b64066e 4 // attention: This program is copyright (c) 2014 by Smartware Computing, all
WiredHome 2:eae60b64066e 5 // rights reserved.
WiredHome 2:eae60b64066e 6 //
WiredHome 2:eae60b64066e 7 // This software, and/or material is the property of Smartware Computing. All
WiredHome 2:eae60b64066e 8 // use, disclosure, and/or reproduction not specifically authorized by Smartware
WiredHome 2:eae60b64066e 9 // Computing is prohibited.
WiredHome 2:eae60b64066e 10 //
WiredHome 2:eae60b64066e 11 // This software may be freely used for non-commercial purposes, and any
WiredHome 2:eae60b64066e 12 // derivative work shall carry the original copyright. The author of
WiredHome 2:eae60b64066e 13 // a derivative work shall make clear that it is a derivative work.
WiredHome 2:eae60b64066e 14 //
WiredHome 2:eae60b64066e 15 // author David Smart, Smartware Computing
WiredHome 2:eae60b64066e 16 //
WiredHome 2:eae60b64066e 17 #include "NWSWeather.h"
WiredHome 0:4435c965d95d 18
WiredHome 10:548533964124 19 #define DEBUG "NWS "
WiredHome 2:eae60b64066e 20 // ...
WiredHome 2:eae60b64066e 21 // INFO("Stuff to show %d", var); // new-line is automatically appended
WiredHome 2:eae60b64066e 22 //
WiredHome 2:eae60b64066e 23 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
WiredHome 11:98afc5abbfb8 24 #define INFO(x, ...) std::printf("[INF %s %3d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 11:98afc5abbfb8 25 #define WARN(x, ...) std::printf("[WRN %s %3d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 11:98afc5abbfb8 26 #define ERR(x, ...) std::printf("[ERR %s %3d] " x "\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 2:eae60b64066e 27 #else
WiredHome 2:eae60b64066e 28 #define INFO(x, ...)
WiredHome 2:eae60b64066e 29 #define WARN(x, ...)
WiredHome 2:eae60b64066e 30 #define ERR(x, ...)
WiredHome 2:eae60b64066e 31 #endif
WiredHome 0:4435c965d95d 32
WiredHome 0:4435c965d95d 33
WiredHome 1:e077d6502c94 34 static NWSWeather::XMLItem_T WeatherData[] = {
WiredHome 1:e077d6502c94 35 {"observation_time_rfc822", NWSWeather::isString},
WiredHome 8:8a3371926b32 36 {"suggested_pickup", NWSWeather::isInt},
WiredHome 1:e077d6502c94 37 {"suggested_pickup_period", NWSWeather::isInt},
WiredHome 1:e077d6502c94 38 {"location", NWSWeather::isString},
WiredHome 1:e077d6502c94 39 {"weather", NWSWeather::isString},
WiredHome 1:e077d6502c94 40 {"temp_f", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 41 {"temp_c", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 42 {"relative_humidity", NWSWeather::isInt},
WiredHome 1:e077d6502c94 43 {"wind_degrees", NWSWeather::isInt},
WiredHome 1:e077d6502c94 44 {"wind_mph", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 45 {"pressure_mb", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 46 {"pressure_in", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 47 {"dewpoint_f", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 48 {"dewpoint_c", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 49 {"windchill_f", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 50 {"windchill_c", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 51 {"visibility_mi", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 52 {"icon_url_base", NWSWeather::isString},
WiredHome 1:e077d6502c94 53 {"icon_url_name", NWSWeather::isString},
WiredHome 1:e077d6502c94 54 {"latitude", NWSWeather::isFloat},
WiredHome 1:e077d6502c94 55 {"longitude", NWSWeather::isFloat},
WiredHome 0:4435c965d95d 56 };
WiredHome 0:4435c965d95d 57
WiredHome 0:4435c965d95d 58 #define MAXPARAMLEN 23
WiredHome 0:4435c965d95d 59
WiredHome 0:4435c965d95d 60 #define WeatherItemCount (sizeof(WeatherData)/sizeof(WeatherData[0]))
WiredHome 0:4435c965d95d 61
WiredHome 0:4435c965d95d 62 NWSWeather::NWSWeather(const char * baseURL)
WiredHome 0:4435c965d95d 63 {
WiredHome 0:4435c965d95d 64 setAlternateURL(baseURL);
WiredHome 0:4435c965d95d 65 }
WiredHome 0:4435c965d95d 66
WiredHome 0:4435c965d95d 67 NWSWeather::~NWSWeather()
WiredHome 0:4435c965d95d 68 {
WiredHome 0:4435c965d95d 69 ClearWeatherRecords();
WiredHome 0:4435c965d95d 70 }
WiredHome 0:4435c965d95d 71
WiredHome 1:e077d6502c94 72 NWSWeather::NWSReturnCode_T NWSWeather::setAlternateURL(const char * baseURL)
WiredHome 0:4435c965d95d 73 {
WiredHome 11:98afc5abbfb8 74 int n = strlen(baseURL)+1;
WiredHome 11:98afc5abbfb8 75
WiredHome 0:4435c965d95d 76 if (m_baseurl)
WiredHome 0:4435c965d95d 77 free(m_baseurl);
WiredHome 11:98afc5abbfb8 78 m_baseurl = (char *)malloc(n);
WiredHome 0:4435c965d95d 79 if (m_baseurl)
WiredHome 11:98afc5abbfb8 80 strncpy(m_baseurl, baseURL, n);
WiredHome 0:4435c965d95d 81 else {
WiredHome 11:98afc5abbfb8 82 ERR("failed to malloc(%d)", n);
WiredHome 0:4435c965d95d 83 return nomemory;
WiredHome 0:4435c965d95d 84 }
WiredHome 0:4435c965d95d 85 ClearWeatherRecords();
WiredHome 0:4435c965d95d 86 return noerror;
WiredHome 0:4435c965d95d 87 }
WiredHome 0:4435c965d95d 88
WiredHome 0:4435c965d95d 89 uint16_t NWSWeather::count(void)
WiredHome 0:4435c965d95d 90 {
WiredHome 0:4435c965d95d 91 return WeatherItemCount;
WiredHome 0:4435c965d95d 92 }
WiredHome 0:4435c965d95d 93
WiredHome 1:e077d6502c94 94 NWSWeather::NWSReturnCode_T NWSWeather::get(const char * site, int responseSize)
WiredHome 0:4435c965d95d 95 {
WiredHome 6:cf96f2787a4e 96 HTTPClient http;
WiredHome 2:eae60b64066e 97 NWSReturnCode_T retCode = nomemory;
WiredHome 2:eae60b64066e 98 char *url = NULL;
WiredHome 0:4435c965d95d 99 char *message = (char *)malloc(responseSize);
WiredHome 0:4435c965d95d 100
WiredHome 2:eae60b64066e 101 INFO("get(%s)", site);
WiredHome 2:eae60b64066e 102 if (!message)
WiredHome 11:98afc5abbfb8 103 ERR("failed to malloc(%d)", responseSize);
WiredHome 2:eae60b64066e 104 while (message) {
WiredHome 11:98afc5abbfb8 105 int n = strlen(m_baseurl) + strlen(site) + 5;
WiredHome 11:98afc5abbfb8 106
WiredHome 11:98afc5abbfb8 107 url = (char *)malloc(n);
WiredHome 0:4435c965d95d 108 if (url) {
WiredHome 0:4435c965d95d 109 strcpy(url, m_baseurl);
WiredHome 0:4435c965d95d 110 strcat(url, site);
WiredHome 0:4435c965d95d 111 strcat(url, ".xml");
WiredHome 2:eae60b64066e 112 INFO(" url: %s", url);
WiredHome 0:4435c965d95d 113 http.setMaxRedirections(3);
WiredHome 0:4435c965d95d 114 int ret = http.get(url, message, responseSize);
WiredHome 0:4435c965d95d 115 if (!ret) {
WiredHome 2:eae60b64066e 116 INFO("ret is %d", ret);
WiredHome 0:4435c965d95d 117 if (http.getHTTPResponseCode() >= 300 && http.getHTTPResponseCode() < 400) {
WiredHome 2:eae60b64066e 118 retCode = noerror; // redirection that was not satisfied.
WiredHome 2:eae60b64066e 119 break;
WiredHome 0:4435c965d95d 120 } else {
WiredHome 6:cf96f2787a4e 121 INFO("wx get %d bytes.\r\n", strlen(message));
WiredHome 0:4435c965d95d 122 ParseWeatherXML(message);
WiredHome 11:98afc5abbfb8 123 INFO("wx parse complete.\r\n");
WiredHome 2:eae60b64066e 124 retCode = noerror;
WiredHome 2:eae60b64066e 125 break;
WiredHome 0:4435c965d95d 126 }
WiredHome 0:4435c965d95d 127 } else {
WiredHome 2:eae60b64066e 128 WARN("get returned %d, no response?", ret);
WiredHome 2:eae60b64066e 129 retCode = noresponse;
WiredHome 2:eae60b64066e 130 break;
WiredHome 0:4435c965d95d 131 }
WiredHome 0:4435c965d95d 132 } else {
WiredHome 11:98afc5abbfb8 133 ERR("failed to malloc(%d)", n);
WiredHome 2:eae60b64066e 134 retCode = nomemory;
WiredHome 2:eae60b64066e 135 break;
WiredHome 2:eae60b64066e 136 }
WiredHome 2:eae60b64066e 137 } // while(...) but configured with break for only 1 pass.
WiredHome 2:eae60b64066e 138 INFO(" ret is %d", retCode);
WiredHome 2:eae60b64066e 139 if (url)
WiredHome 2:eae60b64066e 140 free(url);
WiredHome 2:eae60b64066e 141 if (message)
WiredHome 2:eae60b64066e 142 free(message);
WiredHome 2:eae60b64066e 143 INFO(" mem freed.");
WiredHome 2:eae60b64066e 144 return retCode;
WiredHome 2:eae60b64066e 145 }
WiredHome 2:eae60b64066e 146
WiredHome 2:eae60b64066e 147
WiredHome 2:eae60b64066e 148 NWSWeather::NWSReturnCode_T NWSWeather::isUpdated(uint16_t i)
WiredHome 2:eae60b64066e 149 {
WiredHome 2:eae60b64066e 150 if (i < WeatherItemCount) {
WiredHome 2:eae60b64066e 151 if (WeatherData[i].updated)
WiredHome 2:eae60b64066e 152 return noerror;
WiredHome 2:eae60b64066e 153 else
WiredHome 2:eae60b64066e 154 return noupdate;
WiredHome 2:eae60b64066e 155 } else {
WiredHome 2:eae60b64066e 156 return badparameter;
WiredHome 2:eae60b64066e 157 }
WiredHome 2:eae60b64066e 158 }
WiredHome 2:eae60b64066e 159
WiredHome 2:eae60b64066e 160
WiredHome 2:eae60b64066e 161 NWSWeather::NWSReturnCode_T NWSWeather::isUpdated(const char * name)
WiredHome 2:eae60b64066e 162 {
WiredHome 2:eae60b64066e 163 if (name) {
WiredHome 2:eae60b64066e 164 for (int i=0; i < WeatherItemCount; i++) {
WiredHome 2:eae60b64066e 165 if (strcmp(name, WeatherData[i].name) == 0) {
WiredHome 2:eae60b64066e 166 if (WeatherData[i].updated)
WiredHome 2:eae60b64066e 167 return noerror;
WiredHome 2:eae60b64066e 168 else
WiredHome 2:eae60b64066e 169 return noupdate;
WiredHome 2:eae60b64066e 170 }
WiredHome 0:4435c965d95d 171 }
WiredHome 0:4435c965d95d 172 }
WiredHome 2:eae60b64066e 173 return badparameter;
WiredHome 0:4435c965d95d 174 }
WiredHome 0:4435c965d95d 175
WiredHome 0:4435c965d95d 176
WiredHome 1:e077d6502c94 177 NWSWeather::NWSReturnCode_T NWSWeather::getParam(uint16_t i, char *name, Value_T *value, TypeOf_T *typeis)
WiredHome 0:4435c965d95d 178 {
WiredHome 0:4435c965d95d 179 if (i < WeatherItemCount) {
WiredHome 0:4435c965d95d 180 *name = *WeatherData[i].name;
WiredHome 0:4435c965d95d 181 *value = WeatherData[i].value;
WiredHome 0:4435c965d95d 182 if (typeis)
WiredHome 0:4435c965d95d 183 *typeis = WeatherData[i].typeis;
WiredHome 0:4435c965d95d 184 return noerror;
WiredHome 0:4435c965d95d 185 } else {
WiredHome 0:4435c965d95d 186 return badparameter;
WiredHome 0:4435c965d95d 187 }
WiredHome 0:4435c965d95d 188 }
WiredHome 0:4435c965d95d 189
WiredHome 0:4435c965d95d 190
WiredHome 1:e077d6502c94 191 NWSWeather::NWSReturnCode_T NWSWeather::getParam(const char *name, Value_T *value, TypeOf_T *typeis)
WiredHome 0:4435c965d95d 192 {
WiredHome 2:eae60b64066e 193 for (int i=0; i < WeatherItemCount; i++) {
WiredHome 2:eae60b64066e 194 if (strcmp(name, WeatherData[i].name) == 0) {
WiredHome 2:eae60b64066e 195 *value = WeatherData[i].value;
WiredHome 2:eae60b64066e 196 if (typeis)
WiredHome 2:eae60b64066e 197 *typeis = WeatherData[i].typeis;
WiredHome 2:eae60b64066e 198 return noerror;
WiredHome 0:4435c965d95d 199 }
WiredHome 0:4435c965d95d 200 }
WiredHome 0:4435c965d95d 201 return badparameter;
WiredHome 0:4435c965d95d 202 }
WiredHome 0:4435c965d95d 203
WiredHome 0:4435c965d95d 204
WiredHome 0:4435c965d95d 205 void NWSWeather::ClearWeatherRecords(void)
WiredHome 0:4435c965d95d 206 {
WiredHome 0:4435c965d95d 207 int i;
WiredHome 0:4435c965d95d 208 int count = WeatherItemCount;
WiredHome 0:4435c965d95d 209
WiredHome 0:4435c965d95d 210 for (i=0; i<count; i++) {
WiredHome 0:4435c965d95d 211 switch(WeatherData[i].typeis) {
WiredHome 0:4435c965d95d 212 case isFloat:
WiredHome 0:4435c965d95d 213 WeatherData[i].value.fValue = 0.0;
WiredHome 0:4435c965d95d 214 WeatherData[i].updated = false;
WiredHome 0:4435c965d95d 215 break;
WiredHome 0:4435c965d95d 216 case isInt:
WiredHome 0:4435c965d95d 217 WeatherData[i].value.iValue = 0;
WiredHome 0:4435c965d95d 218 WeatherData[i].updated = false;
WiredHome 0:4435c965d95d 219 break;
WiredHome 0:4435c965d95d 220 case isString:
WiredHome 0:4435c965d95d 221 if (WeatherData[i].value.sValue) {
WiredHome 0:4435c965d95d 222 free(WeatherData[i].value.sValue);
WiredHome 0:4435c965d95d 223 WeatherData[i].value.sValue = NULL;
WiredHome 0:4435c965d95d 224 }
WiredHome 0:4435c965d95d 225 WeatherData[i].updated = false;
WiredHome 0:4435c965d95d 226 break;
WiredHome 0:4435c965d95d 227 default:
WiredHome 0:4435c965d95d 228 break;
WiredHome 0:4435c965d95d 229 }
WiredHome 0:4435c965d95d 230 }
WiredHome 0:4435c965d95d 231 }
WiredHome 0:4435c965d95d 232
WiredHome 0:4435c965d95d 233 void NWSWeather::PrintWeatherRecord(uint16_t i)
WiredHome 0:4435c965d95d 234 {
WiredHome 0:4435c965d95d 235 if (i < WeatherItemCount) {
WiredHome 0:4435c965d95d 236 switch(WeatherData[i].typeis) {
WiredHome 0:4435c965d95d 237 case isFloat:
WiredHome 0:4435c965d95d 238 printf("%23s = %f\r\n", WeatherData[i].name, WeatherData[i].value.fValue);
WiredHome 0:4435c965d95d 239 break;
WiredHome 0:4435c965d95d 240 case isInt:
WiredHome 0:4435c965d95d 241 printf("%23s = %d\r\n", WeatherData[i].name, WeatherData[i].value.iValue);
WiredHome 0:4435c965d95d 242 break;
WiredHome 0:4435c965d95d 243 case isString:
WiredHome 0:4435c965d95d 244 printf("%23s = %s\r\n", WeatherData[i].name, WeatherData[i].value.sValue);
WiredHome 0:4435c965d95d 245 break;
WiredHome 0:4435c965d95d 246 default:
WiredHome 0:4435c965d95d 247 break;
WiredHome 0:4435c965d95d 248 }
WiredHome 0:4435c965d95d 249 }
WiredHome 0:4435c965d95d 250 }
WiredHome 0:4435c965d95d 251
WiredHome 0:4435c965d95d 252 void NWSWeather::PrintAllWeatherRecords(void)
WiredHome 0:4435c965d95d 253 {
WiredHome 0:4435c965d95d 254 for (int i=0; i<WeatherItemCount; i++) {
WiredHome 0:4435c965d95d 255 PrintWeatherRecord(i);
WiredHome 0:4435c965d95d 256 }
WiredHome 0:4435c965d95d 257 }
WiredHome 0:4435c965d95d 258
WiredHome 1:e077d6502c94 259 NWSWeather::NWSReturnCode_T NWSWeather::ParseWeatherRecord(char * p)
WiredHome 0:4435c965d95d 260 {
WiredHome 0:4435c965d95d 261 // <tag_name>value</tag_name>
WiredHome 0:4435c965d95d 262 // p1 p2 p3
WiredHome 0:4435c965d95d 263 char *p1, *p2, *p3;
WiredHome 0:4435c965d95d 264 int i;
WiredHome 11:98afc5abbfb8 265 int n;
WiredHome 0:4435c965d95d 266 int count = WeatherItemCount;
WiredHome 0:4435c965d95d 267
WiredHome 11:98afc5abbfb8 268 INFO("ParseWeatherRecord(%s)", p);
WiredHome 11:98afc5abbfb8 269 p1 = strchr(p, '<'); // Pattern Matching <key>value</key>
WiredHome 0:4435c965d95d 270 if (p1++) {
WiredHome 0:4435c965d95d 271 p2 = strchr(p1+1, '>');
WiredHome 0:4435c965d95d 272 if (p2) {
WiredHome 0:4435c965d95d 273 p3 = strchr(p2+1, '<');
WiredHome 0:4435c965d95d 274 if (p3) {
WiredHome 0:4435c965d95d 275 *p2++ = '\0';
WiredHome 0:4435c965d95d 276 *p3 = '\0';
WiredHome 0:4435c965d95d 277 for (i=0; i<count; i++) {
WiredHome 0:4435c965d95d 278 if (strcmp(p1, WeatherData[i].name) == 0) {
WiredHome 0:4435c965d95d 279 switch(WeatherData[i].typeis) {
WiredHome 0:4435c965d95d 280 case isFloat:
WiredHome 0:4435c965d95d 281 WeatherData[i].value.fValue = atof(p2);
WiredHome 0:4435c965d95d 282 WeatherData[i].updated = true;
WiredHome 0:4435c965d95d 283 break;
WiredHome 0:4435c965d95d 284 case isInt:
WiredHome 0:4435c965d95d 285 WeatherData[i].value.iValue = atoi(p2);
WiredHome 0:4435c965d95d 286 WeatherData[i].updated = true;
WiredHome 0:4435c965d95d 287 break;
WiredHome 0:4435c965d95d 288 case isString:
WiredHome 0:4435c965d95d 289 if (WeatherData[i].value.sValue)
WiredHome 0:4435c965d95d 290 free(WeatherData[i].value.sValue);
WiredHome 11:98afc5abbfb8 291 n = strlen(p2)+1;
WiredHome 11:98afc5abbfb8 292 WeatherData[i].value.sValue = (char *)malloc(n);
WiredHome 0:4435c965d95d 293 if (WeatherData[i].value.sValue) {
WiredHome 0:4435c965d95d 294 strcpy(WeatherData[i].value.sValue, p2);
WiredHome 0:4435c965d95d 295 WeatherData[i].updated = true;
WiredHome 11:98afc5abbfb8 296 } else {
WiredHome 11:98afc5abbfb8 297 ERR("failed to malloc(%d)", n);
WiredHome 11:98afc5abbfb8 298 break;
WiredHome 0:4435c965d95d 299 }
WiredHome 0:4435c965d95d 300 break;
WiredHome 0:4435c965d95d 301 default:
WiredHome 11:98afc5abbfb8 302 ERR("unknown type");
WiredHome 0:4435c965d95d 303 return badparameter;
WiredHome 0:4435c965d95d 304 //break;
WiredHome 0:4435c965d95d 305 }
WiredHome 11:98afc5abbfb8 306 INFO("pw end");
WiredHome 0:4435c965d95d 307 return noerror;
WiredHome 0:4435c965d95d 308 }
WiredHome 0:4435c965d95d 309 }
WiredHome 0:4435c965d95d 310 }
WiredHome 0:4435c965d95d 311 }
WiredHome 0:4435c965d95d 312 }
WiredHome 11:98afc5abbfb8 313 INFO("pw end");
WiredHome 0:4435c965d95d 314 return noparamfound;
WiredHome 0:4435c965d95d 315 }
WiredHome 0:4435c965d95d 316
WiredHome 0:4435c965d95d 317 void NWSWeather::ParseWeatherXML(char * message)
WiredHome 0:4435c965d95d 318 {
WiredHome 0:4435c965d95d 319 char * p = message;
WiredHome 0:4435c965d95d 320
WiredHome 11:98afc5abbfb8 321 INFO("ParseWeatherXML: %s", p);
WiredHome 0:4435c965d95d 322 ClearWeatherRecords();
WiredHome 11:98afc5abbfb8 323 INFO("cleared old");
WiredHome 0:4435c965d95d 324 while (*p) {
WiredHome 0:4435c965d95d 325 char * n = strchr(p, '\n');
WiredHome 0:4435c965d95d 326 if (*n) {
WiredHome 0:4435c965d95d 327 *n = '\0';
WiredHome 0:4435c965d95d 328 ParseWeatherRecord(p);
WiredHome 0:4435c965d95d 329 p = n + 1;
WiredHome 0:4435c965d95d 330 } else {
WiredHome 0:4435c965d95d 331 ParseWeatherRecord(p);
WiredHome 0:4435c965d95d 332 break;
WiredHome 0:4435c965d95d 333 }
WiredHome 0:4435c965d95d 334 }
WiredHome 0:4435c965d95d 335 }