From ee2c65401b4dbfcab611a81c80cf0f4bc76c6364 Mon Sep 17 00:00:00 2001 From: keithfisher123 Date: Sat, 27 Aug 2022 16:31:31 -0700 Subject: [PATCH 1/5] Added Openweather 3.0 API Added v3 OpenWeatherAPI --- OpenWeather3.cpp | 202 +++++++++++++++++++++++++++++++++++++++++++++++ OpenWeather3.h | 21 +++++ 2 files changed, 223 insertions(+) create mode 100644 OpenWeather3.cpp create mode 100644 OpenWeather3.h diff --git a/OpenWeather3.cpp b/OpenWeather3.cpp new file mode 100644 index 0000000..08db7c2 --- /dev/null +++ b/OpenWeather3.cpp @@ -0,0 +1,202 @@ +// OpenWeather3.cpp +// This file manages the retrieval of Weather related information and adjustment of durations +// from OpenWeather + +#include "config.h" +#ifdef WEATHER_OPENWEATHER3 + +#include "OpenWeather3.h" +#include "core.h" +#include "port.h" +#include +#include +#include +#include "json.hpp" + +using json = nlohmann::json; + +OpenWeather3::OpenWeather3(void) +{ + m_openWeatherAPIHost="api.openweathermap.org"; +} + +static void ParseResponse(json &data, Weather::ReturnVals * ret) +{ + freeMemory(); + ret->valid = false; + ret->maxhumidity = -999; + ret->minhumidity = 999; + + float temp=0; + float wind=0; + float rain=0; + float precip=0; + short humidity; + short i=0; + + try { + for (auto &hour : data["hourly"]) { + rain = 0; + temp += hour["temp"].get(); + wind += hour["wind_speed"].get(); + if (hour.count("rain") > 0 && hour["rain"].count("1h") > 0) { + rain = hour["rain"]["1h"].get(); + precip += rain; + } + humidity = hour["humidity"].get(); +/* + trace("collected the following values:\ntemp: %0.2f\nwind: %0.2f\nprecip: %0.2f\nhumid: %0.2f\n", + hour["temp"].get(), hour["wind_speed"].get(), rain, humidity); + + trace("totals so far:\ntemp: %0.2f\nwind: %0.2f\nprecip: %0.2f\n\n", + temp, wind, precip); +*/ + if (humidity > ret->maxhumidity) { + ret->maxhumidity = humidity; + } + if (humidity < ret->minhumidity) { + ret->minhumidity = humidity; + } + if (++i > 24) { + break; + } + } +if (i==0){ +for (auto &hour : data["data"]) { + rain = 0; + temp += hour["temp"].get(); + wind += hour["wind_speed"].get(); + if (hour.count("rain") > 0 && hour["rain"].count("1h") > 0) { + rain = hour["rain"]["1h"].get(); + precip += rain; + } + humidity = hour["humidity"].get(); +/* + trace("collected the following values:\ntemp: %0.2f\nwind: %0.2f\nprecip: %0.2f\nhumid: %0.2f\n", + hour["temp"].get(), hour["wind_speed"].get(), rain, humidity); + trace("totals so far:\ntemp: %0.2f\nwind: %0.2f\nprecip: %0.2f\n\n", + temp, wind, precip); +*/ + if (humidity > ret->maxhumidity) { + ret->maxhumidity = humidity; + } + if (humidity < ret->minhumidity) { + ret->minhumidity = humidity; + } + if (++i > 24) { + break; + } + } +} + +if (i > 0) { + ret->valid = true; + ret->meantempi = (short) std::round(temp/i); + ret->windmph = (short) std::round(wind/i * WIND_FACTOR); + ret->precipi = (short) std::round(precip / MM_TO_IN * PRECIP_FACTOR); // we want total not average + ret->UV = (short) std::round(data["current"]["uvi"].get() * UV_FACTOR); + } + } catch(std::exception &err) { + trace(err.what()); + } + + + if (ret->maxhumidity == -999 || ret->maxhumidity > 100) { + ret->maxhumidity = NEUTRAL_HUMIDITY; + } + if (ret->minhumidity == 999 || ret->minhumidity < 0) { + ret->minhumidity = NEUTRAL_HUMIDITY; + } + + trace("Parsed the following values:\ntemp: %d\nwind: %0.2f\nprecip: %0.2f\nuv: %0.2f\n", + ret->meantempi, ret->windmph/WIND_FACTOR, ret->precipi/PRECIP_FACTOR, ret->UV/UV_FACTOR); +} + +static void GetData(const Weather::Settings & settings,const char *m_openWeatherAPIHost,time_t timestamp, Weather::ReturnVals * ret) +{ + char cmd[255]; + + // split location into lat, long + char * loc = strdup(settings.location); + char * lat = strtok(loc, ", "); + char * lon = strtok(NULL, ", "); + + // get weather json + if (timestamp != 0) { + snprintf(cmd, sizeof(cmd), + "/usr/bin/curl -sS -o /tmp/openWeather.json 'https://%s/data/3.0/onecall/timemachine?appid=%s&lat=%s&lon=%s&dt=%ld&units=imperial'", + m_openWeatherAPIHost, settings.apiSecret, lat, lon, timestamp); + } else { + snprintf(cmd, sizeof(cmd), + "/usr/bin/curl -sS -o /tmp/openWeather.json 'https://%s/data/3.0/onecall?appid=%s&lat=%s&lon=%s&units=imperial'", + m_openWeatherAPIHost, settings.apiSecret, lat, lon); + } + //trace("cmd: %s\n",cmd); + + FILE *fh; + char buf[255]; + + buf[0]=0; + + if ((fh = popen(cmd, "r")) != NULL) { + size_t byte_count = fread(buf, 1, sizeof(buf) - 1, fh); + buf[byte_count] = 0; + } + + (void) pclose(fh); + trace("curl error output: %s\n",buf); + + json j; + std::ifstream ifs("/tmp/openWeather.json"); + ifs >> j; + + ParseResponse(j, ret); + + ifs.close(); + + if (!ret->valid) + { + if (ret->keynotfound) + trace("Invalid OpenWeather Key\n"); + else + trace("Bad OpenWeather Response\n"); + } +} + +Weather::ReturnVals OpenWeather::InternalGetVals(const Weather::Settings & settings) const +{ + ReturnVals vals = {0}; + const time_t now = nntpTimeServer.utcNow(); + + // today + trace("Get Today's Weather\n"); + GetData(settings, m_openWeatherAPIHost, 0, &vals); + if (vals.valid) { + // save today's values + short precip_today = vals.precipi; + short uv_today = vals.UV; + + //trace("local hour: %d\n", nntpTimeServer.LocalHour()); + if (nntpTimeServer.LocalHour() >= 8) { + trace("Get Today's Weather for the hours between midnight and now\n"); + GetData(settings, m_openWeatherAPIHost, now - 8 * 3600, &vals); + if (vals.valid) { + // add precip to today's values + precip_today += vals.precipi; + } + } + + // yesterday + trace("Get Yesterday's Weather\n"); + GetData(settings, m_openWeatherAPIHost, now - 24 * 3600, &vals); + if (vals.valid) { + // restore today's values + vals.precip_today = precip_today; + vals.UV = uv_today; + } + } + + return vals; +} + +#endif diff --git a/OpenWeather3.h b/OpenWeather3.h new file mode 100644 index 0000000..485d587 --- /dev/null +++ b/OpenWeather3.h @@ -0,0 +1,21 @@ +// OpenWeather.h +// This file manages the retrieval of Weather related information and adjustment of durations +// from OpenWeather +// + +#ifndef _OW_h +#define _OW_h + +#include "port.h" +#include "Weather.h" + +class OpenWeather3 : public Weather +{ +public: + OpenWeather3(void); +private: + const char* m_openWeatherAPIHost; + Weather::ReturnVals InternalGetVals(const Weather::Settings & settings) const; +}; + +#endif From d317a4b151794b8ca2d2cb92761902b1f6194519 Mon Sep 17 00:00:00 2001 From: keithfisher123 Date: Sat, 27 Aug 2022 16:38:09 -0700 Subject: [PATCH 2/5] add OpenWeather3 --- config.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/config.h b/config.h index 09a0b23..e4dc843 100644 --- a/config.h +++ b/config.h @@ -32,6 +32,9 @@ // Open Weather https://openweathermap.org/darksky-openweather //#define WEATHER_OPENWEATHER +// Open Weather V3 API https://openweathermap.org/darksky-openweather +//#define WEATHER_OPENWEATHER3 + // Aeris Weather https://www.aerisweather.com //#define WEATHER_AERIS From 5fc747a52f3047f7088dbdcf6f362bc5aac10dd7 Mon Sep 17 00:00:00 2001 From: keithfisher123 Date: Sat, 27 Aug 2022 16:47:23 -0700 Subject: [PATCH 3/5] add weather3 --- CMakeLists.txt | 2 ++ core.cpp | 5 +++++ web.cpp | 10 ++++++++++ 3 files changed, 17 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 949a406..592e6e9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,8 @@ add_executable(sprinklers_pi DarkSky.h OpenWeather.cpp OpenWeather.h + OpenWeather3.cpp + OpenWeather3.h web.cpp web.h json.hpp) diff --git a/core.cpp b/core.cpp index bd3f650..18ab610 100644 --- a/core.cpp +++ b/core.cpp @@ -15,6 +15,8 @@ #include "DarkSky.h" #elif defined(WEATHER_OPENWEATHER) #include "OpenWeather.h" +#elif defined(WEATHER_OPENWEATHER3) +#include "OpenWeather3.h" #else #include "Weather.h" #endif @@ -263,6 +265,9 @@ static runStateClass::DurationAdjustments AdjustDurations(Schedule * sched) DarkSky w; #elif defined(WEATHER_OPENWEATHER) OpenWeather w; +#elif defined(WEATHER_OPENWEATHER3) + OpenWeather3 w; + #else // this is a dummy provider which will just result in 100 Weather w; diff --git a/web.cpp b/web.cpp index f4b0bfb..d60b6ff 100644 --- a/web.cpp +++ b/web.cpp @@ -18,6 +18,9 @@ #include "DarkSky.h" #elif defined(WEATHER_OPENWEATHER) #include "OpenWeather.h" +#elif defined(WEATHER_OPENWEATHER3) +#include "OpenWeather3.h" + #else #include "Weather.h" #endif @@ -261,6 +264,10 @@ static void JSONSettings(const KVPairs & key_value_pairs, FILE * stream_file) #if defined(WEATHER_OPENWEATHER) fprintf_P(stream_file, PSTR("\t\"apisecret\" : \"%s\",\n"), settings.apiSecret); fprintf_P(stream_file, PSTR("\t\"loc\" : \"%s\",\n"), settings.location); +#endif +#if defined(WEATHER_OPENWEATHER3) + fprintf_P(stream_file, PSTR("\t\"apisecret\" : \"%s\",\n"), settings.apiSecret); + fprintf_P(stream_file, PSTR("\t\"loc\" : \"%s\",\n"), settings.location); #endif // leave this value last, it has no comma after the value fprintf_P(stream_file, PSTR("\t\"sadj\" : \"%ld\"\n"), (long) GetSeasonalAdjust()); @@ -280,6 +287,9 @@ static void JSONwCheck(const KVPairs & key_value_pairs, FILE * stream_file) DarkSky w; #elif defined(WEATHER_OPENWEATHER) OpenWeather w; +#elif defined(WEATHER_OPENWEATHER3) + OpenWeather3 w; + #else Weather w; noprovider = true; From 14939f1f6a9df7710aadd7d643e9a229909463fe Mon Sep 17 00:00:00 2001 From: keithfisher123 Date: Sat, 27 Aug 2022 16:54:54 -0700 Subject: [PATCH 4/5] fixed a few bugs --- OpenWeather3.cpp | 2 +- OpenWeather3.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/OpenWeather3.cpp b/OpenWeather3.cpp index 08db7c2..3320cf4 100644 --- a/OpenWeather3.cpp +++ b/OpenWeather3.cpp @@ -163,7 +163,7 @@ static void GetData(const Weather::Settings & settings,const char *m_openWeather } } -Weather::ReturnVals OpenWeather::InternalGetVals(const Weather::Settings & settings) const +Weather::ReturnVals OpenWeather3::InternalGetVals(const Weather::Settings & settings) const { ReturnVals vals = {0}; const time_t now = nntpTimeServer.utcNow(); diff --git a/OpenWeather3.h b/OpenWeather3.h index 485d587..c6f61c3 100644 --- a/OpenWeather3.h +++ b/OpenWeather3.h @@ -1,4 +1,4 @@ -// OpenWeather.h +// OpenWeather3.h // This file manages the retrieval of Weather related information and adjustment of durations // from OpenWeather // From 84cd732f7ed661c6dc2b00830c3400f68a58ef33 Mon Sep 17 00:00:00 2001 From: keithfisher123 Date: Sat, 27 Aug 2022 16:57:42 -0700 Subject: [PATCH 5/5] Update Makefile --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index dcb27d5..00d7575 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,7 @@ Wunderground.cpp \ Aeris.cpp \ DarkSky.cpp \ OpenWeather.cpp \ +OpenWeather3.cpp \ core.cpp \ port.cpp \ settings.cpp \