summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--HISTORY6
-rw-r--r--README4
-rw-r--r--config.c6
-rw-r--r--config.h2
-rw-r--r--libforecastio/forecastio.c138
-rw-r--r--libforecastio/forecastio.h18
-rw-r--r--po/de_DE.po10
-rw-r--r--setup.c22
-rw-r--r--setup.h2
-rw-r--r--weatherforecast.c15
-rw-r--r--weatherosd.c50
11 files changed, 209 insertions, 64 deletions
diff --git a/HISTORY b/HISTORY
index 7bfa408..2cb4f17 100644
--- a/HISTORY
+++ b/HISTORY
@@ -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
diff --git a/README b/README
index 2b83531..074d6a7 100644
--- a/README
+++ b/README
@@ -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:
------
diff --git a/config.c b/config.c
index e7b2293..3762b9d 100644
--- a/config.c
+++ b/config.c
@@ -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;
}
diff --git a/config.h b/config.h
index 6adc3fb..e7812c6 100644
--- a/config.h
+++ b/config.h
@@ -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 ""
diff --git a/setup.c b/setup.c
index 55ad504..07332cb 100644
--- a/setup.c
+++ b/setup.c
@@ -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
diff --git a/setup.h b/setup.h
index 6800bad..b117300 100644
--- a/setup.h
+++ b/setup.h
@@ -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();