Skip to content

Commit

Permalink
Merge pull request #191 from keithfisher123/master
Browse files Browse the repository at this point in the history
Added a Weather Provider for OPEN WEATHER V3.0
  • Loading branch information
nhorvath authored Apr 21, 2024
2 parents 9a58d5c + 84cd732 commit 2add0f2
Show file tree
Hide file tree
Showing 7 changed files with 244 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ add_executable(sprinklers_pi
DarkSky.h
OpenWeather.cpp
OpenWeather.h
OpenWeather3.cpp
OpenWeather3.h
web.cpp
web.h
json.hpp)
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Wunderground.cpp \
Aeris.cpp \
DarkSky.cpp \
OpenWeather.cpp \
OpenWeather3.cpp \
core.cpp \
port.cpp \
settings.cpp \
Expand Down
202 changes: 202 additions & 0 deletions OpenWeather3.cpp
Original file line number Diff line number Diff line change
@@ -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 <string.h>
#include <stdlib.h>
#include <fstream>
#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<float>();
wind += hour["wind_speed"].get<float>();
if (hour.count("rain") > 0 && hour["rain"].count("1h") > 0) {
rain = hour["rain"]["1h"].get<float>();
precip += rain;
}
humidity = hour["humidity"].get<short>();
/*
trace("collected the following values:\ntemp: %0.2f\nwind: %0.2f\nprecip: %0.2f\nhumid: %0.2f\n",
hour["temp"].get<float>(), hour["wind_speed"].get<float>(), 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<float>();
wind += hour["wind_speed"].get<float>();
if (hour.count("rain") > 0 && hour["rain"].count("1h") > 0) {
rain = hour["rain"]["1h"].get<float>();
precip += rain;
}
humidity = hour["humidity"].get<short>();
/*
trace("collected the following values:\ntemp: %0.2f\nwind: %0.2f\nprecip: %0.2f\nhumid: %0.2f\n",
hour["temp"].get<float>(), hour["wind_speed"].get<float>(), 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<float>() * 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 OpenWeather3::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
21 changes: 21 additions & 0 deletions OpenWeather3.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// OpenWeather3.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
3 changes: 3 additions & 0 deletions config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
5 changes: 5 additions & 0 deletions core.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions web.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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());
Expand All @@ -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;
Expand Down

0 comments on commit 2add0f2

Please sign in to comment.