|
| 1 | +// OpenWeather.cpp |
| 2 | +// This file manages the retrieval of Weather related information and adjustment of durations |
| 3 | +// from OpenWeather |
| 4 | + |
| 5 | +#include "config.h" |
| 6 | +#ifdef WEATHER_OPENWEATHER |
| 7 | + |
| 8 | +#include "OpenWeather.h" |
| 9 | +#include "core.h" |
| 10 | +#include "port.h" |
| 11 | +#include <string.h> |
| 12 | +#include <stdlib.h> |
| 13 | +#include <fstream> |
| 14 | +#include "json.hpp" |
| 15 | + |
| 16 | +using json = nlohmann::json; |
| 17 | + |
| 18 | +OpenWeather::OpenWeather(void) |
| 19 | +{ |
| 20 | + m_openWeatherAPIHost="api.openweathermap.org"; |
| 21 | +} |
| 22 | + |
| 23 | +static void ParseResponse(json &data, Weather::ReturnVals * ret) |
| 24 | +{ |
| 25 | + freeMemory(); |
| 26 | + ret->valid = false; |
| 27 | + ret->maxhumidity = -999; |
| 28 | + ret->minhumidity = 999; |
| 29 | + |
| 30 | + float temp=0; |
| 31 | + float wind=0; |
| 32 | + float rain=0; |
| 33 | + float precip=0; |
| 34 | + short humidity; |
| 35 | + short i=0; |
| 36 | + |
| 37 | + try { |
| 38 | + for (auto &hour : data["hourly"]) { |
| 39 | + rain = 0; |
| 40 | + temp += hour["temp"].get<float>(); |
| 41 | + wind += hour["wind_speed"].get<float>(); |
| 42 | + if (hour.count("rain") > 0 && hour["rain"].count("1h") > 0) { |
| 43 | + rain = hour["rain"]["1h"].get<float>(); |
| 44 | + precip += rain; |
| 45 | + } |
| 46 | + humidity = hour["humidity"].get<short>(); |
| 47 | +/* |
| 48 | + trace("collected the following values:\ntemp: %0.2f\nwind: %0.2f\nprecip: %0.2f\nhumid: %0.2f\n", |
| 49 | + hour["temp"].get<float>(), hour["wind_speed"].get<float>(), rain, humidity); |
| 50 | +
|
| 51 | + trace("totals so far:\ntemp: %0.2f\nwind: %0.2f\nprecip: %0.2f\n\n", |
| 52 | + temp, wind, precip); |
| 53 | +*/ |
| 54 | + if (humidity > ret->maxhumidity) { |
| 55 | + ret->maxhumidity = humidity; |
| 56 | + } |
| 57 | + if (humidity < ret->minhumidity) { |
| 58 | + ret->minhumidity = humidity; |
| 59 | + } |
| 60 | + if (++i > 24) { |
| 61 | + break; |
| 62 | + } |
| 63 | + } |
| 64 | + if (i > 0) { |
| 65 | + ret->valid = true; |
| 66 | + ret->meantempi = (short) std::round(temp/i); |
| 67 | + ret->windmph = (short) std::round(wind/i * WIND_FACTOR); |
| 68 | + ret->precipi = (short) std::round(precip / MM_TO_IN * PRECIP_FACTOR); // we want total not average |
| 69 | + ret->UV = (short) std::round(data["current"]["uvi"].get<float>() * UV_FACTOR); |
| 70 | + } |
| 71 | + } catch(std::exception &err) { |
| 72 | + trace(err.what()); |
| 73 | + } |
| 74 | + |
| 75 | + |
| 76 | + if (ret->maxhumidity == -999 || ret->maxhumidity > 100) { |
| 77 | + ret->maxhumidity = NEUTRAL_HUMIDITY; |
| 78 | + } |
| 79 | + if (ret->minhumidity == 999 || ret->minhumidity < 0) { |
| 80 | + ret->minhumidity = NEUTRAL_HUMIDITY; |
| 81 | + } |
| 82 | + |
| 83 | + trace("Parsed the following values:\ntemp: %d\nwind: %0.2f\nprecip: %0.2f\nuv: %0.2f\n", |
| 84 | + ret->meantempi, ret->windmph/WIND_FACTOR, ret->precipi/PRECIP_FACTOR, ret->UV/UV_FACTOR); |
| 85 | +} |
| 86 | + |
| 87 | +static void GetData(const Weather::Settings & settings,const char *m_openWeatherAPIHost,time_t timestamp, Weather::ReturnVals * ret) |
| 88 | +{ |
| 89 | + char cmd[255]; |
| 90 | + |
| 91 | + // split location into lat, long |
| 92 | + char * pch; |
| 93 | + char * loc = strdup(settings.location); |
| 94 | + char * lat = strtok(loc, ", "); |
| 95 | + char * lon = strtok(NULL, ", "); |
| 96 | + |
| 97 | + // get weather json |
| 98 | + if (timestamp != 0) { |
| 99 | + snprintf(cmd, sizeof(cmd), |
| 100 | + "/usr/bin/curl -sS -o /tmp/openWeather.json 'https://%s/data/2.5/onecall/timemachine?appid=%s&lat=%s&lon=%s&dt=%ld&units=imperial'", |
| 101 | + m_openWeatherAPIHost, settings.apiSecret, lat, lon, timestamp); |
| 102 | + } else { |
| 103 | + snprintf(cmd, sizeof(cmd), |
| 104 | + "/usr/bin/curl -sS -o /tmp/openWeather.json 'https://%s/data/2.5/onecall?appid=%s&lat=%s&lon=%s&units=imperial'", |
| 105 | + m_openWeatherAPIHost, settings.apiSecret, lat, lon); |
| 106 | + } |
| 107 | + //trace("cmd: %s\n",cmd); |
| 108 | + |
| 109 | + FILE *fh; |
| 110 | + char buf[255]; |
| 111 | + |
| 112 | + buf[0]=0; |
| 113 | + |
| 114 | + if ((fh = popen(cmd, "r")) != NULL) { |
| 115 | + size_t byte_count = fread(buf, 1, sizeof(buf) - 1, fh); |
| 116 | + buf[byte_count] = 0; |
| 117 | + } |
| 118 | + |
| 119 | + (void) pclose(fh); |
| 120 | + trace("curl error output: %s\n",buf); |
| 121 | + |
| 122 | + json j; |
| 123 | + std::ifstream ifs("/tmp/openWeather.json"); |
| 124 | + ifs >> j; |
| 125 | + |
| 126 | + ParseResponse(j, ret); |
| 127 | + |
| 128 | + ifs.close(); |
| 129 | + |
| 130 | + if (!ret->valid) |
| 131 | + { |
| 132 | + if (ret->keynotfound) |
| 133 | + trace("Invalid OpenWeather Key\n"); |
| 134 | + else |
| 135 | + trace("Bad OpenWeather Response\n"); |
| 136 | + } |
| 137 | +} |
| 138 | + |
| 139 | +Weather::ReturnVals OpenWeather::InternalGetVals(const Weather::Settings & settings) const |
| 140 | +{ |
| 141 | + ReturnVals vals = {0}; |
| 142 | + const time_t now = nntpTimeServer.utcNow(); |
| 143 | + |
| 144 | + // today |
| 145 | + trace("Get Today's Weather\n"); |
| 146 | + GetData(settings, m_openWeatherAPIHost, 0, &vals); |
| 147 | + if (vals.valid) { |
| 148 | + // save today's values |
| 149 | + short precip_today = vals.precipi; |
| 150 | + short uv_today = vals.UV; |
| 151 | + |
| 152 | + //trace("local hour: %d\n", nntpTimeServer.LocalHour()); |
| 153 | + if (nntpTimeServer.LocalHour() >= 8) { |
| 154 | + trace("Get Today's Weather for the hours between midnight and now\n"); |
| 155 | + GetData(settings, m_openWeatherAPIHost, now - 8 * 3600, &vals); |
| 156 | + if (vals.valid) { |
| 157 | + // add precip to today's values |
| 158 | + precip_today += vals.precipi; |
| 159 | + } |
| 160 | + } |
| 161 | + |
| 162 | + // yesterday |
| 163 | + trace("Get Yesterday's Weather\n"); |
| 164 | + GetData(settings, m_openWeatherAPIHost, now - 24 * 3600, &vals); |
| 165 | + if (vals.valid) { |
| 166 | + // restore today's values |
| 167 | + vals.precip_today = precip_today; |
| 168 | + vals.UV = uv_today; |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + return vals; |
| 173 | +} |
| 174 | + |
| 175 | +#endif |
0 commit comments