diff options
author | louis <louis.braun@gmx.de> | 2015-01-17 10:23:39 +0100 |
---|---|---|
committer | louis <louis.braun@gmx.de> | 2015-01-17 10:23:39 +0100 |
commit | a5aa281e337f148e27b17c287e04d8a023856667 (patch) | |
tree | 6ff69709bfd9815ece9b29a31ae8397653ff8848 | |
parent | c7f71f3f2b580714bd9e5a5c773bc2179c0e8567 (diff) | |
download | vdr-plugin-weatherforecast-0.0.2.tar.gz vdr-plugin-weatherforecast-0.0.2.tar.bz2 |
added possibility to use own api key0.0.2
-rw-r--r-- | HISTORY | 6 | ||||
-rw-r--r-- | README | 4 | ||||
-rw-r--r-- | config.c | 6 | ||||
-rw-r--r-- | config.h | 2 | ||||
-rw-r--r-- | libforecastio/forecastio.c | 138 | ||||
-rw-r--r-- | libforecastio/forecastio.h | 18 | ||||
-rw-r--r-- | po/de_DE.po | 10 | ||||
-rw-r--r-- | setup.c | 22 | ||||
-rw-r--r-- | setup.h | 2 | ||||
-rw-r--r-- | weatherforecast.c | 15 | ||||
-rw-r--r-- | weatherosd.c | 50 |
11 files changed, 209 insertions, 64 deletions
@@ -4,3 +4,9 @@ VDR Plugin 'weatherforecast' Revision History 2015-01-15: Version 0.0.1 - Initial revision. + +- Added possibility to use own API Key, with own API Key + it is possible to configure individual cache duration + of forecast + +Version 0.0.2 @@ -52,6 +52,10 @@ setup menu. f you change latitude or longitude, just delete the cached weather.json file and restart VDR to achieve new data for the newly configured location. +You can configure your own API Key in Plugin Setup. If an own API Key is configured, +you're allowed to change the update frequency from forecast.io individually, update +frequency can then be a value between 1 and 24h. + Usage: ------ @@ -3,11 +3,15 @@ cWeatherforecastConfig::cWeatherforecastConfig() { //number of hours to wait till next update from forecast.io is fetched hoursToUpdate = 20; + //if own API Key is set, user can configure its own udate frequence + userHoursToUpdate = 0; //city to display in menus city = ""; //latitude and longitude of location for forecast.io query lat = 0.0; lon = 0.0; + //User can configure individual API Key + userApiKey = ""; } cWeatherforecastConfig::~cWeatherforecastConfig() { @@ -17,6 +21,8 @@ bool cWeatherforecastConfig::SetupParse(const char *Name, const char *Value) { if (!strcasecmp(Name, "city")) city = Value; else if (!strcasecmp(Name, "lat")) lat = atod(Value); else if (!strcasecmp(Name, "lon")) lon = atod(Value); + else if (!strcasecmp(Name, "userapikey")) userApiKey = Value; + else if (!strcasecmp(Name, "updatefreq")) userHoursToUpdate = atoi(Value); else return false; return true; } @@ -13,8 +13,10 @@ public: ~cWeatherforecastConfig(); bool SetupParse(const char *Name, const char *Value); int hoursToUpdate; + int userHoursToUpdate; string city; float lat; float lon; + string userApiKey; }; #endif //__WEATHERFORECAST_CONFIG_H diff --git a/libforecastio/forecastio.c b/libforecastio/forecastio.c index 1a8db4e..83b9df9 100644 --- a/libforecastio/forecastio.c +++ b/libforecastio/forecastio.c @@ -11,9 +11,8 @@ using namespace std; extern cWeatherforecastConfig weatherConfig; cForecastIO::cForecastIO(string cacheDir) { - this->cacheDir = cacheDir; - ok = false; - cacheDuration = 60 * 60 * weatherConfig.hoursToUpdate; + forecastFile = *cString::sprintf("%s/%s", cacheDir.c_str(), "weather.json"); + cacheDurationDefault = 60 * 60 * weatherConfig.hoursToUpdate; apiKey = "9830052ef63efbec84ec0639e9a205d2"; string osdLanguage = Setup.OSDLanguage; language = osdLanguage.substr(0,2); @@ -27,27 +26,42 @@ cForecastIO::cForecastIO(string cacheDir) { } cForecastIO::~cForecastIO() { - if (current) - delete current; - if (hourly) - delete hourly; - if (daily) - delete daily; + Clear(); } /***************************************************************** * PUBLIC FUNCTIONS *****************************************************************/ void cForecastIO::Action(void) { - ok = ReadForecast(); + loopActive = true; + ReadForecastInitial(); + waitMutex.Lock(); + while (loopActive && Running()) { + waitCondition.TimedWait(waitMutex, 1000 * 60); + if (!loopActive) + return; + if (!CacheFileValid()) { + ReadForecast(); + } + } +} + +void cForecastIO::Stop() { + loopActive = false; + waitCondition.Broadcast(); + Cancel(1); + while (Active()) + cCondWait::SleepMs(10); } cForecast *cForecastIO::GetCurrentForecast(void) { time_t now = time(0); - if (current && current->TimeMatch(now)) + if (current && current->TimeMatch(now)) { return current; - if (hourly) + } + if (hourly) { return hourly->GetCurrent(); + } return NULL; } @@ -55,6 +69,7 @@ bool cForecastIO::SetCurrentWeather(cServiceCurrentWeather *call) { cForecast *currentForecast = GetCurrentForecast(); if (!currentForecast) return false; + call->timeStamp = currentForecast->GetDateTimeString(); call->temperature = currentForecast->GetTemperatureString(); call->apparentTemperature = currentForecast->GetApparentTemperatureString(); @@ -75,6 +90,7 @@ bool cForecastIO::SetCurrentWeather(cServiceCurrentWeather *call) { cForecast *dailyForecast = daily->GetFirstDaily(); if (!dailyForecast) return true; + call->minTemperature = dailyForecast->GetTemperatureMinString(); call->maxTemperature = dailyForecast->GetTemperatureMaxString(); @@ -84,41 +100,93 @@ bool cForecastIO::SetCurrentWeather(cServiceCurrentWeather *call) { /***************************************************************** * PRIVATE FUNCTIONS *****************************************************************/ -bool cForecastIO::ReadForecast(void) { - string forecastFile = *cString::sprintf("%s/%s", cacheDir.c_str(), "weather.json"); - dsyslog("weatherforecast: trying to read cached forecast from %s", forecastFile.c_str()); - string forecastJson = ""; + +void cForecastIO::Clear(void) { + if (current) { + delete current; + current = NULL; + } + if (hourly) { + delete hourly; + hourly = NULL; + } + if (daily) { + delete daily; + daily = NULL; + } +} + +bool cForecastIO::CheckUserApiKey(void) { + if (weatherConfig.userApiKey.size() == 0) + return false; + if (weatherConfig.userApiKey.compare(apiKey) == 0) { + return false; + } + return true; +} + +int cForecastIO::CalculateCachDuration(void) { + if (!CheckUserApiKey()) + return cacheDurationDefault; + if (weatherConfig.userHoursToUpdate > 0 && weatherConfig.userHoursToUpdate <= 24) { + return weatherConfig.userHoursToUpdate * 60 * 60; + } + return cacheDurationDefault; +} + +bool cForecastIO::CacheFileValid(void) { if (!FileExists(forecastFile)) { + dsyslog("weatherforecast: no cached forecast available"); + return false; + } + int cacheDuration = CalculateCachDuration(); + time_t fileCreation = FileCreationTime(forecastFile); + time_t now = time(0); + int age = now - fileCreation; + int ageHours = age / 3600; + int ageMinutes = (age%3600) / 60; + if (age > cacheDuration) { + dsyslog("weatherforecast: cached forecast is outdated (age %dh %dmin, cache duration %dh)", ageHours, ageMinutes, cacheDuration / 3600); + return false; + } + return true; +} + +void cForecastIO::ReadForecastInitial(void) { + string forecastJson = ""; + if (!CacheFileValid()) { //get new from forecast.io - dsyslog("weatherforecast: no cached forecast, fetching newly from forecast.io"); + dsyslog("weatherforecast: fetching forecast newly from forecast.io"); forecastJson = FetchOnlineForecast(); WriteIntoFile(forecastFile, forecastJson); } else { - //check if cached file is too old - time_t fileCreation = FileCreationTime(forecastFile); - time_t now = time(0); - int age = now - fileCreation; - int ageHours = age / 3600; - int ageMinutes = (age%3600) / 60; - if (age > cacheDuration) { - //get new from forecast.io - dsyslog("weatherforecast: cached forecast is with %dh %dmin too old, fetching newly from forecast.io", ageHours, ageMinutes); - forecastJson = FetchOnlineForecast(); - WriteIntoFile(forecastFile, forecastJson); - } else { - //using cached data - dsyslog("weatherforecast: cached forecast is only %dh %dmin old, using cached forecast", ageHours, ageMinutes); - forecastJson = ReadFromFile(forecastFile); - } + //using cached data + dsyslog("weatherforecast: using cached forecast"); + forecastJson = ReadFromFile(forecastFile); } ParseForecast(forecastJson); - return true; +} + +void cForecastIO::ReadForecast(void) { + dsyslog("weatherforecast: updating forecast from forecast.io"); + string forecastJson = ""; + forecastJson = FetchOnlineForecast(); + if (forecastJson.size() > 0) { + WriteIntoFile(forecastFile, forecastJson); + Lock(); + Clear(); + ParseForecast(forecastJson); + Unlock(); + } } string cForecastIO::FetchOnlineForecast(void) { + string myApiKey = apiKey; + if (CheckUserApiKey()) + myApiKey = weatherConfig.userApiKey; stringstream url; - url << baseURL << "/" << apiKey; + url << baseURL << "/" << myApiKey; url << "/" << latitude << "," << longitude; url << "?lang=" << language << "&units=" << unit; string outputForecastIO; diff --git a/libforecastio/forecastio.h b/libforecastio/forecastio.h index c016fb2..bc45e2c 100644 --- a/libforecastio/forecastio.h +++ b/libforecastio/forecastio.h @@ -10,9 +10,8 @@ using namespace std; class cForecastIO : public cThread { private: - bool ok; - string cacheDir; - int cacheDuration; + string forecastFile; + int cacheDurationDefault; string apiKey; string language; string unit; @@ -22,13 +21,24 @@ private: cForecast *current; cForecasts *hourly; cForecasts *daily; + bool loopActive; + cCondVar waitCondition; + cMutex waitMutex; + bool CheckUserApiKey(void); + int CalculateCachDuration(void); + bool CacheFileValid(void); string FetchOnlineForecast(void); bool ParseForecast(string &jsonForecast); void Action(void); - bool ReadForecast(void); + void Clear(void); + void ReadForecastInitial(void); + void ReadForecast(void); public: cForecastIO(string cacheDir); virtual ~cForecastIO(void); + void Stop(void); + void LockForecasts(void) { Lock(); }; + void UnlockForecasts(void) { Unlock(); }; cForecast *GetCurrentForecast(void); cForecasts *GetHourlyForecast(void) { return hourly; }; cForecasts *GetDailyForecast(void) { return daily; }; diff --git a/po/de_DE.po b/po/de_DE.po index 429fe53..54e187e 100644 --- a/po/de_DE.po +++ b/po/de_DE.po @@ -6,7 +6,7 @@ msgid "" msgstr "" "Project-Id-Version: vdr-weatherforecast 0.0.1\n" "Report-Msgid-Bugs-To: <see README>\n" -"POT-Creation-Date: 2015-01-14 13:26+0100\n" +"POT-Creation-Date: 2015-01-16 14:50+0100\n" "PO-Revision-Date: 2015-01-12 11:46+0100\n" "Last-Translator: Louis Braun <louis.braun@gmx.de>\n" "Language-Team: \n" @@ -19,11 +19,17 @@ msgid "City" msgstr "Wohnort" msgid "Latitude" -msgstr "LatÃtude" +msgstr "Latitude" msgid "Longitude" msgstr "Longitude" +msgid "API Key" +msgstr "" + +msgid "Update Frequency in hours" +msgstr "" + msgid "Weather Forecast" msgstr "" @@ -2,12 +2,13 @@ #include "tools/jsonhelpers.h" cWeatherforecastSetup::cWeatherforecastSetup() { - data = weatherConfig; - strn0cpy(city, data.city.c_str(), sizeof(city)); - string strLat = FloatToString(data.lat); - string strLon = FloatToString(data.lon); + strn0cpy(city, weatherConfig.city.c_str(), sizeof(city)); + string strLat = FloatToString(weatherConfig.lat); + string strLon = FloatToString(weatherConfig.lon); strn0cpy(lat, strLat.c_str(), sizeof(lat)); strn0cpy(lon, strLon.c_str(), sizeof(lon)); + strn0cpy(userApiKey, weatherConfig.userApiKey.c_str(), sizeof(userApiKey)); + userHoursToUpdate = weatherConfig.userHoursToUpdate; Setup(); } @@ -22,6 +23,11 @@ void cWeatherforecastSetup::Setup(void) { Add(new cMenuEditStrItem(tr("City"), city, sizeof(city), trVDR(FileNameChars))); Add(new cMenuEditStrItem(tr("Latitude"), lat, sizeof(lat), trVDR(FileNameChars))); Add(new cMenuEditStrItem(tr("Longitude"), lon, sizeof(lon), trVDR(FileNameChars))); + Add(new cMenuEditStrItem(tr("API Key"), userApiKey, sizeof(userApiKey), trVDR(FileNameChars))); + + if (strlen(userApiKey) > 0) { + Add(new cMenuEditIntItem(tr("Update Frequency in hours"), &userHoursToUpdate, 1, 24)); + } SetCurrent(Get(current)); Display(); @@ -29,19 +35,19 @@ void cWeatherforecastSetup::Setup(void) { eOSState cWeatherforecastSetup::ProcessKey(eKeys Key) { eOSState state = cMenuSetupPage::ProcessKey(Key); - switch (state) { - default: break; - } return state; } void cWeatherforecastSetup::Store(void) { - weatherConfig = data; SetupStore("city", city); SetupStore("lat", lat); SetupStore("lon", lon); + SetupStore("userapikey", userApiKey); + SetupStore("updatefreq", userHoursToUpdate); weatherConfig.city = city; weatherConfig.lat = atod(lat); weatherConfig.lon = atod(lon); + weatherConfig.userApiKey = userApiKey; + weatherConfig.userHoursToUpdate = userHoursToUpdate; }
\ No newline at end of file @@ -13,6 +13,8 @@ class cWeatherforecastSetup : public cMenuSetupPage { char city[100]; char lat[10]; char lon[10]; + char userApiKey[100]; + int userHoursToUpdate; private: cWeatherforecastConfig data; void Setup(void); diff --git a/weatherforecast.c b/weatherforecast.c index 49c01ee..5d82fda 100644 --- a/weatherforecast.c +++ b/weatherforecast.c @@ -18,7 +18,7 @@ //*************************************************************************** // Constants //*************************************************************************** -static const char *VERSION = "0.0.1"; +static const char *VERSION = "0.0.2"; static const char *DESCRIPTION = "Weatherforecast based on forecast.io"; static const char *MAINMENUENTRY = "WeatherForecast"; @@ -61,8 +61,9 @@ cPluginWeatherforecast::cPluginWeatherforecast(void) { } cPluginWeatherforecast::~cPluginWeatherforecast() { - if (forecastIO) + if (forecastIO) { delete forecastIO; + } } const char *cPluginWeatherforecast::CommandLineHelp(void) { @@ -108,7 +109,9 @@ bool cPluginWeatherforecast::Start(void) { } void cPluginWeatherforecast::Stop(void) { - + if (forecastIO) { + forecastIO->Stop(); + } } void cPluginWeatherforecast::Housekeeping(void) { @@ -145,7 +148,11 @@ bool cPluginWeatherforecast::Service(const char *Id, void *Data) { return false; if (strcmp(Id, "GetCurrentWeather") == 0) { cServiceCurrentWeather* call = (cServiceCurrentWeather*) Data; - return forecastIO->SetCurrentWeather(call); + bool ok = false; + forecastIO->LockForecasts(); + ok = forecastIO->SetCurrentWeather(call); + forecastIO->UnlockForecasts(); + return ok; } return false; } diff --git a/weatherosd.c b/weatherosd.c index af1ba8f..553c95d 100644 --- a/weatherosd.c +++ b/weatherosd.c @@ -68,6 +68,8 @@ void cWeatherOsd::SetRootMenu(void) { Clear(); SetTitle(tr("Weather Forecast")); + forecastIO->LockForecasts(); + cSkindesignerOsdItem *currentWeather = new cSkindesignerOsdItem(); string itemLabelCurrent = tr("Current Weather"); currentWeather->SetText(itemLabelCurrent.c_str()); @@ -187,6 +189,8 @@ void cWeatherOsd::SetRootMenu(void) { } } + forecastIO->UnlockForecasts(); + Add(nextDays, (lastRootMenuElement == 2)?true:false); Display(); @@ -198,15 +202,29 @@ void cWeatherOsd::SetDetailViewCurrent(void) { ClearTokens(); Clear(); SetTitle(tr("Current Weather")); - cForecast *current = forecastIO->GetCurrentForecast(); - if (!current) - return; - cForecasts *daily = forecastIO->GetDailyForecast(); - if (!daily) - return; - cForecast *today = daily->GetFirstDaily(); - if (!today) + + cForecast *current = NULL; + cForecasts *daily = NULL; + cForecast *today = NULL; + + forecastIO->LockForecasts(); + bool ok = true; + + current = forecastIO->GetCurrentForecast(); + if (!current) ok = false; + + if (ok) + daily = forecastIO->GetDailyForecast(); + if (!daily) ok = false; + + if (ok) + today = daily->GetFirstDaily(); + if (!today) ok = false; + + if (!ok) { + forecastIO->UnlockForecasts(); return; + } stringstream plainText; plainText << tr("Weather for") << " " << weatherConfig.city << " " << current->GetDateTimeString() << ": " << current->GetSummary() << "\n"; @@ -249,6 +267,8 @@ void cWeatherOsd::SetDetailViewCurrent(void) { AddStringToken("pressure", current->GetPressureString()); AddStringToken("ozone", current->GetOzoneString()); + forecastIO->UnlockForecasts(); + Display(); } @@ -259,9 +279,12 @@ void cWeatherOsd::SetDetailViewHourly(void) { ClearTokens(); SetTitle(tr("Weather in the next 48 Hours")); + forecastIO->LockForecasts(); cForecasts *hourly = forecastIO->GetHourlyForecast(); - if (!hourly) + if (!hourly) { + forecastIO->UnlockForecasts(); return; + } stringstream plainText; cForecast *fc = hourly->GetFirstHourly(); @@ -304,7 +327,8 @@ void cWeatherOsd::SetDetailViewHourly(void) { fc = hourly->GetNext(); } - + forecastIO->UnlockForecasts(); + SetText(plainText.str().c_str()); Display(); } @@ -316,9 +340,12 @@ void cWeatherOsd::SetDetailViewDaily(void) { ClearTokens(); SetTitle(tr("Weather the next 7 days")); + forecastIO->LockForecasts(); cForecasts *daily = forecastIO->GetDailyForecast(); - if (!daily) + if (!daily) { + forecastIO->UnlockForecasts(); return; + } stringstream plainText; cForecast *fc = daily->GetFirstDaily(); @@ -365,6 +392,7 @@ void cWeatherOsd::SetDetailViewDaily(void) { fc = daily->GetNext(); } + forecastIO->UnlockForecasts(); SetText(plainText.str().c_str()); Display(); |