David Smart / NWSWeather
Revision:
18:699590fd8856
Parent:
17:99f09cc697fb
Child:
19:00af774c9b72
diff -r 99f09cc697fb -r 699590fd8856 NWSWeather.cpp
--- a/NWSWeather.cpp	Wed Jan 09 12:39:06 2019 +0000
+++ b/NWSWeather.cpp	Mon Jan 14 03:21:13 2019 +0000
@@ -46,63 +46,12 @@
 };
 #define HDR_PAIRS 3
 
-#if WEATHER_GOV == 1
-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},
-};
-#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
-
-#define WeatherItemCount (sizeof(WeatherData)/sizeof(WeatherData[0]))
-
-NWSWeather::NWSWeather(const char * baseURL) : m_baseurl(0)
+NWSWeather::NWSWeather(XMLItem_T * pList, int count) : m_baseurl(0)
 {
-    setAlternateURL(baseURL);
+    WeatherData = pList;
+    WeatherItemCount = count;
+    setAlternateURL(DEF_URL);
 }
 
 NWSWeather::~NWSWeather()
@@ -159,9 +108,6 @@
         url = (char *)swMalloc(n);
         if (url) {
             #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);
@@ -221,7 +167,7 @@
 {
     if (name) {
         for (int i=0; i < WeatherItemCount; i++) {
-            if (strcmp(name, WeatherData[i].name) == 0) {
+            if (strcmp(name, WeatherData[i].key) == 0) {
                 if (WeatherData[i].updated)
                     return noerror;
                 else
@@ -236,7 +182,7 @@
 NWSWeather::NWSReturnCode_T NWSWeather::getParam(uint16_t i, char *name, Value_T *value, TypeOf_T *typeis)
 {
     if (i < WeatherItemCount) {
-        *name = *WeatherData[i].name;
+        *name = *WeatherData[i].key;
         *value = WeatherData[i].value;
         if (typeis)
             *typeis = WeatherData[i].typeis;
@@ -249,12 +195,20 @@
 
 NWSWeather::NWSReturnCode_T NWSWeather::getParam(const char *name, Value_T *value, TypeOf_T *typeis)
 {
+    return getParam(name, NULL, value, typeis);
+}
+
+
+NWSWeather::NWSReturnCode_T NWSWeather::getParam(const char *name, const char * param, 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;
+        if (strcmp(name, WeatherData[i].key) == 0) {
+            if (param == NULL || strcmp(param, WeatherData[i].param) == 0) {
+                *value = WeatherData[i].value;
+                if (typeis)
+                    *typeis = WeatherData[i].typeis;
+                return noerror;
+            }
         }
     }
     return badparameter;
@@ -292,19 +246,21 @@
 void NWSWeather::PrintWeatherRecord(uint16_t i)
 {
     if (i < WeatherItemCount) {
+        printf("%23s::%-10s = ", WeatherData[i].key, WeatherData[i].param);
         switch(WeatherData[i].typeis) {
             case isFloat:
-                printf("%23s = %f\r\n", WeatherData[i].name, WeatherData[i].value.fValue);
+                printf("%f", WeatherData[i].value.fValue);
                 break;
             case isInt:
-                printf("%23s = %d\r\n", WeatherData[i].name, WeatherData[i].value.iValue);
+                printf("%d", WeatherData[i].value.iValue);
                 break;
             case isString:
-                printf("%23s = %s\r\n", WeatherData[i].name, WeatherData[i].value.sValue);
+                printf("%s", WeatherData[i].value.sValue);
                 break;
             default:
                 break;
         }
+        printf("\r\n");
     }
 }
 
@@ -315,8 +271,107 @@
     }
 }
 
+NWSWeather::NWSReturnCode_T NWSWeather::ExtractParam(int i, char * pValue, char * pEnd) {
+    int n;
+    
+    INFO("ExtractParam(%d, ...)", i);
+    switch(WeatherData[i].typeis) {
+        case isFloat:
+            WeatherData[i].value.fValue = (float)atof(pValue);
+            WeatherData[i].updated = true;
+            INFO("%f", WeatherData[i].value.fValue);
+            break;
+        case isInt:
+            WeatherData[i].value.iValue = atoi(pValue);
+            WeatherData[i].updated = true;
+            INFO("%d", WeatherData[i].value.iValue);
+            break;
+        case isString:
+            if (WeatherData[i].value.sValue)
+                swFree(WeatherData[i].value.sValue);
+            n = pEnd - pValue;
+            WeatherData[i].value.sValue = (char *)swMalloc(n+1);
+            if (WeatherData[i].value.sValue) {
+                strncpy(WeatherData[i].value.sValue, pValue, n);
+                WeatherData[i].value.sValue[n] = '\0';
+                WeatherData[i].updated = true;
+                INFO(" info '%s'", WeatherData[i].value.sValue);
+            } else {
+                ERR("failed to swMalloc(%d)", n);
+                return nomemory;
+            }
+            break;
+        default:
+            ERR("unknown type");
+            return badparameter;
+            //break;
+    }
+    INFO("...");
+    return noerror;
+}
+
 NWSWeather::NWSReturnCode_T NWSWeather::ParseWeatherRecord(char * p)
 {
+    #if 1
+    // Pattern Matching <thekey dontcare="something" value="thevalue"/>
+    //                   |     |                     |------|       | |
+    //                   |     |                     |              | +pEnd
+    //                   |     +pKeyE                +pVal          +pValE
+    //                   +pKey
+    //
+    //                  <thekey>theValue</thekey>
+    //                   |     ||       |       |
+    //                   |     ||       |       +pEnd
+    //                   |     |+pVal   +pValE
+    //                   |     +pKeyE
+    //                   +pKey
+    //
+    char *pKey, *pEnd;
+    char *pVal = NULL;
+    char *pValE = NULL;
+
+    p = strchr(p, '<');
+    while (p) {
+        //INFO("ParseWeatherRecord  \n%s\n", p);
+        p++;    // Advance past the '<'
+        for (int i=0; i<WeatherItemCount; i++) {
+            //INFO("\n  check %s::%s", WeatherData[i].key, WeatherData[i].param);
+            pKey = strstr(p, WeatherData[i].key);
+            if (pKey && pKey == p && *(pKey-1) == '<') {
+                //INFO("  key %s", pKey);
+                if (WeatherData[i].param && WeatherData[i].param[0]) {
+                    // <thekey dontcare="something" value="thevalue"/>
+                    pEnd = strchr(pKey, '/');
+                    if (pEnd) {
+                        pVal = strstr(pKey, WeatherData[i].param);
+                        if (pVal && pVal < pEnd) {
+                            pVal = strchr(pVal, '"');
+                            if (pVal) {
+                                pVal++;
+                                //INFO("  val %s", pVal);
+                                pValE = strchr(pVal, '"');
+                                ExtractParam(i, pVal, pValE);
+                                INFO("Key %s::%s", WeatherData[i].key, WeatherData[i].param);
+                            }
+                        }
+                    }
+                } else {
+                    // <thekey>theValue</key>
+                    pVal = strchr(pKey, '>');
+                    if (pVal) {
+                        pVal++;
+                        pValE = strchr(pVal, '<');
+                        if (pValE && *(pValE+1) == '/') {
+                            ExtractParam(i, pVal, pValE);
+                            INFO("Key %s", WeatherData[i].key);
+                        }
+                    }
+                }
+            }
+        }
+        p = strchr(p, '<');
+    }
+    #else
     // <tag_name>value</tag_name>
     //  pKey     pValue
     char *pKey, *pValue, *pX;
@@ -365,7 +420,7 @@
     #endif
     if (parseIt) {
         for (i=0; i<count; i++) {
-            if (strcmp(pKey, WeatherData[i].name) == 0) {
+            if (strcmp(pKey, WeatherData[i].key) == 0) {
                 switch(WeatherData[i].typeis) {
                     case isFloat:
                         WeatherData[i].value.fValue = atof(pValue);
@@ -395,36 +450,18 @@
                         return badparameter;
                         //break;
                 }
-                //INFO("pw end");
                 return noerror;
             }
         }
     }
-    //INFO("pw end");
+    #endif
     return noparamfound;
 }
 
 void NWSWeather::ParseWeatherXML(char * message)
 {
-    char * p = message;
+    char * p = strchr(message, '<');
 
-    INFO("ParseWeatherXML: %s", p);
     ClearWeatherRecords();
-    INFO("cleared old");
-    while (*p) {
-        char * n;
-        #if WEATHER_GOV == 1
-        n = strchr(p, '\n');
-        #elif OPEN_WEATHER == 1
-        n = strchr(p, '>');
-        #endif
-        if (*n) {
-            *n = '\0';
-            ParseWeatherRecord(p);
-            p = n + 1;
-        } else {
-            ParseWeatherRecord(p);
-            break;
-        }
-    }
+    ParseWeatherRecord(p);
 }