David Smart / NWSWeather
Revision:
17:99f09cc697fb
Parent:
16:dd56cf216433
Child:
18:699590fd8856
diff -r dd56cf216433 -r 99f09cc697fb NWSWeather.cpp
--- a/NWSWeather.cpp	Sun Nov 13 02:08:54 2016 +0000
+++ b/NWSWeather.cpp	Wed Jan 09 12:39:06 2019 +0000
@@ -1,7 +1,7 @@
 // 
 // This file contains the interface for gathering forecast from NWS.
 //
-// attention: This program is copyright (c) 2014 - 2015 by Smartware Computing, all 
+// 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
@@ -22,7 +22,7 @@
 #define swFree free
 #endif
 
-//#define DEBUG "NWS "
+#define DEBUG "NWS "
 // ...
 // INFO("Stuff to show %d", var); // new-line is automatically appended
 //
@@ -46,29 +46,55 @@
 };
 #define HDR_PAIRS 3
 
+#if WEATHER_GOV == 1
 static NWSWeather::XMLItem_T WeatherData[] = {
-    {"observation_time_rfc822", NWSWeather::isString},
+    {"observation_time_rfc822", NWSWeather::isString},  //
     {"suggested_pickup", NWSWeather::isInt},
     {"suggested_pickup_period", NWSWeather::isInt},
-    {"location", NWSWeather::isString},
-    {"weather", NWSWeather::isString},
-    {"temp_f",  NWSWeather::isFloat},
+    {"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},
+    {"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},
+    {"visibility_mi", NWSWeather::isFloat},             //
     {"icon_url_base", NWSWeather::isString},
     {"icon_url_name", NWSWeather::isString},
     {"latitude", NWSWeather::isFloat},
     {"longitude", NWSWeather::isFloat},
 };
+#elif OPEN_WEATHER == 1
+static NWSWeather::XMLItem_T WeatherData[] = {
+    {"lastupdate", NWSWeather::isString},               //<lastupdate value="2019-01-09T00:15:00"/>
+    {"city", NWSWeather::isString},                     //<city id="4880889" name="Waterloo">
+    {"weather", NWSWeather::isString},                  //<weather number="802" value="scattered clouds" icon="03n"/>
+    {"temperature",  NWSWeather::isFloat},              //<temperature value="27.3" min="21.2" max="32" unit="fahrenheit"/>
+    {"humidity", NWSWeather::isInt},                    //<humidity value="68" unit="%"/>
+    {"direction", NWSWeather::isInt},                   //<direction value="310" code="NW" name="Northwest"/>
+    {"speed", NWSWeather::isFloat},                     //<speed value="26.4" name="Storm"/>
+    {"pressure", NWSWeather::isInt},                    //<pressure value="1021" unit="hPa"/>
+    {"visibility", NWSWeather::isInt},                  //<visibility value="16093"/>
+    {"sun*rise", NWSWeather::isString},                 //<sun rise="2019-01-09T13:38:27" set="2019-01-09T22:54:45"/>
+    {"sun*set", NWSWeather::isString},                  //<sun rise="2019-01-09T13:38:27" set="2019-01-09T22:54:45"/>
+};
+//<current>
+//<coord lon="-92.34" lat="42.49"/>
+//<country>US</country>
+//</city>
+//<wind>
+//<gusts value="19"/>
+//</wind>
+//<clouds value="40" name="scattered clouds"/>
+//<precipitation mode="no"/>
+//</current>
+#endif
 
 #define MAXPARAMLEN 23
 
@@ -106,7 +132,11 @@
     return WeatherItemCount;
 }
 
+#if WEATHER_GOV == 1
 NWSWeather::NWSReturnCode_T NWSWeather::get(const char * site, int responseSize)
+#elif OPEN_WEATHER == 1
+NWSWeather::NWSReturnCode_T NWSWeather::get(const char * site, const char * userid, int responseSize)
+#endif
 {
     HTTPClient http;
     NWSReturnCode_T retCode = nomemory;
@@ -117,13 +147,25 @@
     if (!message)
         ERR("failed to swMalloc(%d)", responseSize);
     while (message) {
+        #if WEATHER_GOV == 1
+        //https://www.weather.gov/data/current_obs/<loc_code>.xml
+        //                                                   ++++
         int n = strlen(m_baseurl) + strlen(site) + 5;
-        
+        #elif OPEN_WEATHER == 1
+        //http://api.openweathermap.org/data/2.5/weather?mode=xml&units=imperial&id=<loc_code>&APPID=<user_id>
+        //                                                                      ++++          +++++++
+        int n = strlen(m_baseurl) + 4 + strlen(site) + 7 + strlen(userid) + 1;
+        #endif
         url = (char *)swMalloc(n);
         if (url) {
-            strcpy(url, m_baseurl);
-            strcat(url, site);
-            strcat(url, ".xml");
+            #if WEATHER_GOV == 1
+            //strcpy(url, m_baseurl);
+            //strcat(url, site);
+            //strcat(url, ".xml");
+            sprintf(url, "%s%s%s.xml", m_baseurl, site);
+            #elif OPEN_WEATHER == 1
+            sprintf(url, "%s&id=%s&APPID=%s", m_baseurl, site, userid);
+            #endif
             INFO("  url: %s", url);
             http.setMaxRedirections(3);
             http.customHeaders(hdrs, HDR_PAIRS);
@@ -276,56 +318,85 @@
 NWSWeather::NWSReturnCode_T NWSWeather::ParseWeatherRecord(char * p)
 {
     // <tag_name>value</tag_name>
-    //  p1       p2   p3
-    char *p1, *p2, *p3;
+    //  pKey     pValue
+    char *pKey, *pValue, *pX;
     int i;
     int n;
     int count = WeatherItemCount;
+    bool parseIt = false;
 
     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;
+    #if WEATHER_GOV == 1
+    // Pattern Matching <key>value</key>
+    //                   |   +pValue
+    //                   +pKey
+    pKey = strchr(p, '<');
+    if (pKey++) {
+        pValue = strchr(pKey+1, '>');
+        if (pValue) {
+            p2 = strchr(pValue+1, '<');
+            if (p2) {
+                *pValue++ = '\0';
+                *p2 = '\0';
+                parseIt = true;
+            }
+        }
+    }
+    #elif OPEN_WEATHER == 1
+    pKey = strchr(p, '<');
+    // Pattern Matching <key dontcare="something" value="thevalue" dontcare="something"/>
+    //                   |                               +pValue
+    //                   +pKey
+    if (pKey++) {
+        pValue = strchr(pKey+1, ' ');
+        if (pValue) {
+            *pValue++ = '\0';
+            pValue = strstr(pValue, "value=\"");
+            if (pValue) {
+                pValue += 7;
+                pX = strchr(pValue, '"');
+                if (pX) {
+                    *pX = '\0';
+                    parseIt = true;
+                }
+            }
+        }
+    }
+    #endif
+    if (parseIt) {
+        for (i=0; i<count; i++) {
+            if (strcmp(pKey, WeatherData[i].name) == 0) {
+                switch(WeatherData[i].typeis) {
+                    case isFloat:
+                        WeatherData[i].value.fValue = atof(pValue);
+                        WeatherData[i].updated = true;
+                        break;
+                    case isInt:
+                        WeatherData[i].value.iValue = atoi(pValue);
+                        WeatherData[i].updated = true;
+                        break;
+                    case isString:
+                        if (WeatherData[i].value.sValue)
+                            swFree(WeatherData[i].value.sValue);
+                        n = strlen(pValue)+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, pValue);
+                            WeatherData[i].updated = true;
+                        } else {
+                            ERR("failed to swMalloc(%d)", n);
+                            break;
                         }
-                        //INFO("pw end");
-                        return noerror;
-                    }
+                        break;
+                    default:
+                        ERR("unknown type");
+                        return badparameter;
+                        //break;
                 }
+                //INFO("pw end");
+                return noerror;
             }
         }
     }
@@ -341,7 +412,12 @@
     ClearWeatherRecords();
     INFO("cleared old");
     while (*p) {
-        char * n = strchr(p, '\n');
+        char * n;
+        #if WEATHER_GOV == 1
+        n = strchr(p, '\n');
+        #elif OPEN_WEATHER == 1
+        n = strchr(p, '>');
+        #endif
         if (*n) {
             *n = '\0';
             ParseWeatherRecord(p);