David Smart / NWSWeather

NWSWeather.cpp

Committer:
WiredHome
Date:
2014-03-16
Revision:
0:4435c965d95d
Child:
1:e077d6502c94

File content as of revision 0:4435c965d95d:


#include "NWSWeather.h"


static XMLItem_T WeatherData[] = {
    {"observation_time_rfc822", isString, false, NULL},
    {"suggested_pickup", isString, false, NULL},
    {"suggested_pickup_period", isInt, false, 0},
    {"location", isString, false, NULL},
    {"weather", isString, false, NULL},
    {"temp_f",  isFloat, false, 0},
    {"temp_c",  isFloat, false, 0},
    {"relative_humidity", isInt, false, 0},
    {"wind_degrees", isInt, false, 0},
    {"wind_mph", isFloat, false, 0},
    {"pressure_mb", isFloat},
    {"pressure_in", isFloat, false, 0},
    {"dewpoint_f", isFloat},
    {"dewpoint_c", isFloat},
    {"windchill_f", isInt, false, 0},
    {"windchill_c", isInt, false, 0},
    {"visibility_mi", isFloat},
    {"icon_url_base", isString, false, NULL},
    {"icon_url_name", isString, false, NULL},
    {"latitude", isFloat, false, 0},
    {"longitude", isFloat, false, 0},
};

#define MAXPARAMLEN 23

#define WeatherItemCount (sizeof(WeatherData)/sizeof(WeatherData[0]))

NWSWeather::NWSWeather(const char * baseURL)
{
    setAlternateURL(baseURL);
}

NWSWeather::~NWSWeather()
{
    ClearWeatherRecords();
}

NWSReturnCode_T NWSWeather::setAlternateURL(const char * baseURL)
{
    if (m_baseurl)
        free(m_baseurl);
    m_baseurl = (char *)malloc(strlen(baseURL)+1);
    if (m_baseurl)
        strcpy(m_baseurl, baseURL);
    else {
        return nomemory;
    }
    ClearWeatherRecords();
    return noerror;
}

uint16_t NWSWeather::count(void)
{
    return WeatherItemCount;
}

NWSReturnCode_T NWSWeather::get(const char * site, int responseSize)
{
    Timer timer;
    char *message = (char *)malloc(responseSize);

    if (message) {
        char * url = (char *)malloc(strlen(m_baseurl) + strlen(site) + 5);
        if (url) {
            strcpy(url, m_baseurl);
            strcat(url, site);
            strcat(url, ".xml");
            http.setMaxRedirections(3);
            //printf("get(%s)\r\n", url);
            timer.start();
            int ret = http.get(url, message, responseSize);
            int elapsed = timer.read_ms();
            if (!ret) {
                if (http.getHTTPResponseCode() >= 300 && http.getHTTPResponseCode() < 400) {
                    return noerror;         // redirection that was not satisfied.
                } else {
                    ParseWeatherXML(message);
                    return noerror;
                }
            } else {
                return noresponse;
            }
        } else {
            return nomemory;
        }
    }
    return nomemory;
}


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;
    }
}


NWSReturnCode_T NWSWeather::isUpdated(uint16_t i)
{
    if (i < WeatherItemCount && WeatherData[i].updated)
        return noerror;
    else
        return noupdate;
}


NWSReturnCode_T NWSWeather::getParam(const char *name, Value_T *value, TypeOf_T *typeis)
{
    if (value) {
        for (int i=0; i < WeatherItemCount; i++) {
            //printf("Compare(%s,%s)\r\n", name, WeatherData[i].name);
            if (strcmp(name, WeatherData[i].name) == 0) {
                *value = WeatherData[i].value;
                //printf("  assignment.\r\n");
                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) {
                    free(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);
    }
}

NWSReturnCode_T NWSWeather::ParseWeatherRecord(char * p)
{
    // <tag_name>value</tag_name>
    //  p1       p2   p3
    char *p1, *p2, *p3;
    int i;
    int count = WeatherItemCount;

    //printf("::%s::\r\n", p);
    p1 = strchr(p, '<');
    if (p1++) {
        p2 = strchr(p1+1, '>');
        if (p2) {
            p3 = strchr(p2+1, '<');
            if (p3) {
                *p2++ = '\0';
                *p3 = '\0';
                //printf("tag: %s, value: %s\r\n", p1, p2);
                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)
                                    free(WeatherData[i].value.sValue);
                                WeatherData[i].value.sValue = (char *)malloc(strlen(p2)+1);
                                if (WeatherData[i].value.sValue) {
                                    strcpy(WeatherData[i].value.sValue, p2);
                                    WeatherData[i].updated = true;
                                }
                                break;
                            default:
                                return badparameter;
                                //break;
                        }
                        //PrintWeatherRecord(i);
                        return noerror;
                    }
                }
            }
        }
    }
    return noparamfound;
}

void NWSWeather::ParseWeatherXML(char * message)
{
    char * p = message;

    ClearWeatherRecords();
    while (*p) {
        char * n = strchr(p, '\n');
        if (*n) {
            *n = '\0';
            ParseWeatherRecord(p);
            p = n + 1;
        } else {
            ParseWeatherRecord(p);
            break;
        }
    }
}