mirror of
https://github.com/Llewellynvdm/conky.git
synced 2025-01-12 19:06:36 +00:00
Revert "Undid last 3 commits, see rest of the comment for the reason:"
First of all, we may or may not agree, but I consider reverting my
commits without prior discussion as a minimum unpolite.
I also don't like sites that oblige to register, thats the very reason
why I went with noaa first (and why I use that myself).
Howver, weather.com has a couple of nice features forom an user
viewpoint:
1. Their icons can be used to add a visual quality to the weather
report.
2. They have forecast data, which is not possible to have with noaa
(using TAF its an option, but its going to be very difficult and will
be limited in time and scope).
Nobody is obliged to do anything, people who likes noaa will use noaa,
people that don't mind register or wants the additional benefit will use
weather.com.
Having libxms2 as a dragged depends is, first of all, also with other
options (rss and eve), second we can try to work around it with an
additional compilation flag if really deemed necessary.
This reverts commit d872562942
.
This commit is contained in:
parent
d872562942
commit
3bb9b4b6b5
@ -1,3 +1,6 @@
|
||||
2009-07-18
|
||||
* www.weather.com can now be used as well as a source of weather data
|
||||
|
||||
2009-07-11
|
||||
* Added support for $desktop, $desktop_number and $desktop_name (sf.net #2040528)
|
||||
|
||||
|
@ -356,9 +356,10 @@ AC_ARG_ENABLE([weather],
|
||||
#
|
||||
AM_CONDITIONAL(BUILD_WEATHER, test x$want_weather = xyes)
|
||||
if test x$want_weather = xyes; then
|
||||
PKG_CHECK_MODULES([libxml2], libxml-2.0)
|
||||
PKG_CHECK_MODULES([libcurl], libcurl)
|
||||
conky_CFLAGS="$conky_CFLAGS $libcurl_CFLAGS"
|
||||
conky_LIBS="$conky_LIBS $libcurl_LIBS"
|
||||
conky_CFLAGS="$conky_CFLAGS $libxml2_CFLAGS $libcurl_CFLAGS"
|
||||
conky_LIBS="$conky_LIBS $libxml2_LIBS $libcurl_LIBS"
|
||||
AC_DEFINE(WEATHER, 1, [Define if you want weather support])
|
||||
fi
|
||||
|
||||
@ -706,6 +707,7 @@ dnl
|
||||
|
||||
AC_DEFINE(DEFAULTNETDEV, "eth0", [Default networkdevice])
|
||||
AC_DEFINE(CONFIG_FILE, "$HOME/.conkyrc", [Configfile of the user])
|
||||
AC_DEFINE(XOAP_FILE, "$HOME/.xoaprc", [User xoap keys file])
|
||||
AC_DEFINE(MAX_SPECIALS_DEFAULT, 512, [Default maximum number of special things, e.g. fonts, offsets, aligns, etc.])
|
||||
AC_DEFINE(MAX_USER_TEXT_DEFAULT, 16384, [Default maximum size of config TEXT buffer, i.e. below TEXT line.])
|
||||
AC_DEFINE(DEFAULT_TEXT_BUFFER_SIZE, 256, [Default size used for temporary, static text buffers])
|
||||
|
@ -3290,23 +3290,40 @@
|
||||
<command>
|
||||
<option>weather</option>
|
||||
</command>
|
||||
<option>URI icao data_type (delay_in_minutes)</option>
|
||||
<option>URI locID data_type (delay_in_minutes)</option>
|
||||
</term>
|
||||
<listitem>
|
||||
<para>Download, parse and display METAR data.</para>
|
||||
<para>For the 'URI', right now only
|
||||
http://weather.noaa.gov/pub/data/observations/metar/stations/
|
||||
is supported. Other sources might be supported in the future.
|
||||
<para>For the 'URI', there are two possibilities:</para>
|
||||
<simplelist>
|
||||
<member>
|
||||
http://weather.noaa.gov/pub/data/observations/metar/stations/
|
||||
</member>
|
||||
<member>
|
||||
http://xoap.weather.com/weather/local/
|
||||
</member>
|
||||
</simplelist>
|
||||
<para>The first one is free to use but the second requires you to
|
||||
register and obtain your partner ID and license key.
|
||||
These two must be written, separated by a space, into a file
|
||||
called .xoaprc which needs to be placed into your home directory.
|
||||
</para>
|
||||
<para>'icao' must be a valid icao for the required location
|
||||
<para>'locID' must be a valid location identifier for the required
|
||||
uri. For the NOAA site this must be a valid ICAO
|
||||
(see for instance https://pilotweb.nas.faa.gov/qryhtml/icao/).
|
||||
For the weather.com site this must be a valid location ID
|
||||
(see for instance http://aspnetresources.com/tools/locid.aspx).
|
||||
</para>
|
||||
<para>'data_type' must be one of the following:</para>
|
||||
<simplelist>
|
||||
<member>
|
||||
<command>last_update</command>
|
||||
<option>The date (yyyy/mm/dd) and time (UTC) of
|
||||
the last update</option>
|
||||
<option>The date and time stamp of the data.
|
||||
The result depends on the URI used. For the NOAA site
|
||||
it is date (yyyy/mm/dd) and UTC time. For the
|
||||
weather.com one it is date ([m]m/[d]d/yy) and Local Time
|
||||
of the station.
|
||||
</option>
|
||||
</member>
|
||||
<member>
|
||||
<command>temperature</command>
|
||||
@ -3319,7 +3336,7 @@
|
||||
<option>The highest cloud cover status</option>
|
||||
</member>
|
||||
<member>
|
||||
<command>pressurer</command>
|
||||
<command>pressure</command>
|
||||
<option>Air pressure in millibar</option>
|
||||
</member>
|
||||
<member>
|
||||
@ -3341,7 +3358,9 @@
|
||||
<member>
|
||||
<command>weather</command>
|
||||
<option>Any relevant weather event (rain, snow,
|
||||
etc.))</option>
|
||||
etc.). This is not used if you are querying the
|
||||
weather.com site since this data is aggregated
|
||||
into the cloud_cover one</option>
|
||||
</member>
|
||||
</simplelist>
|
||||
<para>'delay_in_minutes' (optional, default 30) cannot be
|
||||
|
97
src/conky.c
97
src/conky.c
@ -318,6 +318,11 @@ static int cpu_avg_samples, net_avg_samples, diskio_avg_samples;
|
||||
char *overwrite_file = NULL; FILE *overwrite_fpointer = NULL;
|
||||
char *append_file = NULL; FILE *append_fpointer = NULL;
|
||||
|
||||
/* xoap suffix for weather from weather.com */
|
||||
#ifdef WEATHER
|
||||
static char *xoap = NULL;
|
||||
#endif /* WEATHER */
|
||||
|
||||
#ifdef X11
|
||||
|
||||
static int show_graph_scale;
|
||||
@ -2820,35 +2825,53 @@ static struct text_object *construct_text_object(const char *s,
|
||||
END OBJ_THREAD(weather, 0)
|
||||
if (arg) {
|
||||
int argc, interval;
|
||||
char *icao = (char *) malloc(5 * sizeof(char));
|
||||
char *locID = (char *) malloc(9 * sizeof(char));
|
||||
char *uri = (char *) malloc(128 * sizeof(char));
|
||||
char *data_type = (char *) malloc(32 * sizeof(char));
|
||||
char *tmp_p;
|
||||
|
||||
argc = sscanf(arg, "%119s %4s %31s %d", uri, icao, data_type, &interval);
|
||||
argc = sscanf(arg, "%119s %8s %31s %d", uri, locID, data_type, &interval);
|
||||
|
||||
//icao MUST BE upper-case
|
||||
tmp_p = icao;
|
||||
//locID MUST BE upper-case
|
||||
tmp_p = locID;
|
||||
while (*tmp_p) {
|
||||
*tmp_p = toupper(*tmp_p);
|
||||
tmp_p++;
|
||||
*tmp_p = toupper(*tmp_p);
|
||||
tmp_p++;
|
||||
}
|
||||
|
||||
//Construct complete uri
|
||||
if (strstr(uri, "xoap.weather.com")) {
|
||||
if(xoap != NULL) {
|
||||
strcat(uri, locID);
|
||||
strcat(uri, xoap);
|
||||
} else {
|
||||
free(uri);
|
||||
uri = NULL;
|
||||
}
|
||||
} else if (strstr(uri, "weather.noaa.gov")) {
|
||||
strcat(uri, locID);
|
||||
strcat(uri, ".TXT");
|
||||
} else if (!strstr(uri, "localhost") && !strstr(uri, "127.0.0.1")) {
|
||||
CRIT_ERR(obj, free_at_crash, \
|
||||
"could not recognize the weather uri");
|
||||
}
|
||||
|
||||
strcat(uri, icao);
|
||||
strcat(uri, ".TXT");
|
||||
obj->data.weather.uri = uri;
|
||||
|
||||
obj->data.weather.data_type = data_type;
|
||||
|
||||
// The data retrieval interval is limited to half an hour
|
||||
//Limit the data retrieval interval to half hour min
|
||||
if (interval < 30) {
|
||||
interval = 30;
|
||||
}
|
||||
obj->data.weather.interval = interval * 60; // convert to seconds
|
||||
free(icao);
|
||||
|
||||
//Convert to seconds
|
||||
obj->data.weather.interval = interval * 60;
|
||||
free(locID);
|
||||
|
||||
DBGP("weather: fetching %s from %s every %d seconds", \
|
||||
data_type, uri, obj->data.weather.interval);
|
||||
} else {
|
||||
CRIT_ERR(obj, free_at_crash, "weather needs arguments: <uri> <icao> <data_type> [interval in minutes]");
|
||||
CRIT_ERR(obj, free_at_crash, "weather needs arguments: <uri> <locID> <data_type> [interval in minutes]");
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_LUA
|
||||
@ -4647,7 +4670,11 @@ static void generate_text_internal(char *p, int p_max_size,
|
||||
#endif
|
||||
#ifdef WEATHER
|
||||
OBJ(weather) {
|
||||
process_weather_info(p, p_max_size, obj->data.weather.uri, obj->data.weather.data_type, obj->data.weather.interval);
|
||||
if( obj->data.weather.uri != NULL ) {
|
||||
process_weather_info(p, p_max_size, obj->data.weather.uri, obj->data.weather.data_type, obj->data.weather.interval);
|
||||
} else {
|
||||
strncpy(p, "invalid xoap keys file", p_max_size);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_LUA
|
||||
@ -8885,6 +8912,42 @@ static void load_config_file_x11(const char *f)
|
||||
}
|
||||
#endif /* X11 */
|
||||
|
||||
#ifdef WEATHER
|
||||
/*
|
||||
* TODO: make the xoap keys file readable from the config file
|
||||
* make the keys directly readable from the config file
|
||||
* make the xoap keys file giveable as a command line option
|
||||
*/
|
||||
static void load_xoap_keys(void)
|
||||
{
|
||||
FILE *fp;
|
||||
char *par = (char *) malloc(11 * sizeof(char));
|
||||
char *key = (char *) malloc(17 * sizeof(char));
|
||||
|
||||
xoap = (char *) malloc(64 * sizeof(char));
|
||||
to_real_path(xoap, XOAP_FILE);
|
||||
fp = fopen(xoap, "r");
|
||||
if (fp != NULL) {
|
||||
if( fscanf(fp, "%10s %16s", par, key) == 2 ) {
|
||||
strcpy(xoap, "?cc=*&link=xoap&prod=xoap&par=");
|
||||
strcat(xoap, par);
|
||||
strcat(xoap, "&key=");
|
||||
strcat(xoap, key);
|
||||
strcat(xoap, "&unit=m");
|
||||
} else {
|
||||
free(xoap);
|
||||
xoap = NULL;
|
||||
}
|
||||
fclose(fp);
|
||||
} else {
|
||||
free(xoap);
|
||||
xoap = NULL;
|
||||
}
|
||||
free(par);
|
||||
free(key);
|
||||
}
|
||||
#endif /* WEATHER */
|
||||
|
||||
static void print_help(const char *prog_name) {
|
||||
printf("Usage: %s [OPTION]...\n"
|
||||
PACKAGE_NAME" is a system monitor that renders text on desktop or to own transparent\n"
|
||||
@ -9268,6 +9331,12 @@ int main(int argc, char **argv)
|
||||
#endif /* ! CONF_OUTPUT */
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef WEATHER
|
||||
/* Load xoap keys, if existing */
|
||||
load_xoap_keys();
|
||||
#endif /* WEATHER */
|
||||
|
||||
#ifdef HAVE_SYS_INOTIFY_H
|
||||
inotify_fd = inotify_init();
|
||||
#endif /* HAVE_SYS_INOTIFY_H */
|
||||
|
137
src/weather.c
137
src/weather.c
@ -21,6 +21,11 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* TODO: Add weather forecast info from weather.com
|
||||
*
|
||||
*/
|
||||
|
||||
#include "conky.h"
|
||||
#include "logging.h"
|
||||
#include "weather.h"
|
||||
@ -33,6 +38,7 @@
|
||||
#include <curl/curl.h>
|
||||
#include <curl/types.h>
|
||||
#include <curl/easy.h>
|
||||
#include <libxml/parser.h>
|
||||
|
||||
/* Possible sky conditions */
|
||||
#define NUM_CC_CODES 6
|
||||
@ -120,6 +126,75 @@ int rel_humidity(int dew_point, int air) {
|
||||
#endif /* MATH */
|
||||
}
|
||||
|
||||
//TODO: Lets get rid of the recursion
|
||||
static void parse_cc(PWEATHER *res, xmlNodePtr cc)
|
||||
{
|
||||
|
||||
xmlNodePtr cur = NULL;
|
||||
|
||||
for (cur = cc; cur; cur = cur->next) {
|
||||
if (cur->type == XML_ELEMENT_NODE) {
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *) "lsup")) {
|
||||
strncpy(res->lastupd, (char *)cur->children->content, 31);
|
||||
} else if (!xmlStrcmp(cur->name, (const xmlChar *) "tmp")) {
|
||||
res->temp = atoi((char *)cur->children->content);
|
||||
} else if (!xmlStrcmp(cur->name, (const xmlChar *) "t")) {
|
||||
if(res->xoap_t[0] == '\0') {
|
||||
strncpy(res->xoap_t, (char *)cur->children->content, 31);
|
||||
}
|
||||
} else if (!xmlStrcmp(cur->name, (const xmlChar *) "r")) {
|
||||
res->bar = atoi((char *)cur->children->content);
|
||||
} else if (!xmlStrcmp(cur->name, (const xmlChar *) "s")) {
|
||||
res->wind_s = atoi((char *)cur->children->content);
|
||||
} else if (!xmlStrcmp(cur->name, (const xmlChar *) "d")) {
|
||||
if (isdigit((char)cur->children->content[0])) {
|
||||
res->wind_d = atoi((char *)cur->children->content);
|
||||
}
|
||||
} else if (!xmlStrcmp(cur->name, (const xmlChar *) "hmid")) {
|
||||
res->hmid = atoi((char *)cur->children->content);
|
||||
}
|
||||
}
|
||||
parse_cc(res, cur->children);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void parse_weather_xml(PWEATHER *res, const char *data)
|
||||
{
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr cur;
|
||||
|
||||
if (!(doc = xmlReadMemory(data, strlen(data), "", NULL, 0))) {
|
||||
ERR("weather: can't read xml data");
|
||||
return;
|
||||
}
|
||||
|
||||
cur = xmlDocGetRootElement(doc);
|
||||
|
||||
while(cur) {
|
||||
if (cur->type == XML_ELEMENT_NODE) {
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *) "weather")) {
|
||||
cur = cur->children;
|
||||
while (cur != NULL) {
|
||||
if (cur->type == XML_ELEMENT_NODE) {
|
||||
if (!xmlStrcmp(cur->name, (const xmlChar *) "cc")) {
|
||||
parse_cc(res, cur->children);
|
||||
xmlFreeDoc(doc);
|
||||
return;
|
||||
}
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
ERR("weather: incorrect xml data");
|
||||
xmlFreeDoc(doc);
|
||||
return ;
|
||||
}
|
||||
|
||||
/*
|
||||
* Horrible hack to avoid using regexes
|
||||
*
|
||||
@ -337,6 +412,7 @@ static inline void parse_token(PWEATHER *res, char *token) {
|
||||
|
||||
//First 3 digits are wind direction
|
||||
strncpy(s_tmp, token, 3);
|
||||
s_tmp[3]='\0';
|
||||
res->wind_d=atoi(s_tmp);
|
||||
|
||||
//4th and 5th digit are wind speed in knots (convert to km/hr)
|
||||
@ -393,6 +469,7 @@ static inline void parse_token(PWEATHER *res, char *token) {
|
||||
|
||||
//First 3 digits are wind direction
|
||||
strncpy(s_tmp, token, 3);
|
||||
s_tmp[3]='\0';
|
||||
res->wind_d=atoi(s_tmp);
|
||||
|
||||
//4th and 5th digit are wind speed in m/s (convert to km/hr)
|
||||
@ -410,38 +487,44 @@ static inline void parse_token(PWEATHER *res, char *token) {
|
||||
|
||||
static void parse_weather(PWEATHER *res, const char *data)
|
||||
{
|
||||
char s_tmp[256];
|
||||
const char delim[] = " ";
|
||||
|
||||
//Reset results
|
||||
memset(res, 0, sizeof(PWEATHER));
|
||||
|
||||
//Divide time stamp and metar data
|
||||
if (sscanf(data, "%[^'\n']\n%[^'\n']", res->lastupd, s_tmp) == 2) {
|
||||
//Check if it is an xml file
|
||||
if ( strncmp(data, "<?xml ", 6) == 0 ) {
|
||||
parse_weather_xml(res, data);
|
||||
} else {
|
||||
//We assume its a text file
|
||||
char s_tmp[256];
|
||||
const char delim[] = " ";
|
||||
|
||||
//Process all tokens
|
||||
char *p_tok = NULL;
|
||||
char *p_save = NULL;
|
||||
//Divide time stamp and metar data
|
||||
if (sscanf(data, "%[^'\n']\n%[^'\n']", res->lastupd, s_tmp) == 2) {
|
||||
|
||||
if ((strtok_r(s_tmp, delim, &p_save)) != NULL) {
|
||||
//Process all tokens
|
||||
char *p_tok = NULL;
|
||||
char *p_save = NULL;
|
||||
|
||||
//Jump first token, must be icao
|
||||
p_tok = strtok_r(NULL, delim, &p_save);
|
||||
if ((strtok_r(s_tmp, delim, &p_save)) != NULL) {
|
||||
|
||||
do {
|
||||
//Jump first token, must be icao
|
||||
p_tok = strtok_r(NULL, delim, &p_save);
|
||||
|
||||
parse_token(res, p_tok);
|
||||
p_tok = strtok_r(NULL, delim, &p_save);
|
||||
do {
|
||||
|
||||
} while (p_tok != NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
parse_token(res, p_tok);
|
||||
p_tok = strtok_r(NULL, delim, &p_save);
|
||||
|
||||
} while (p_tok != NULL);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void fetch_weather_info(location *curloc)
|
||||
{
|
||||
CURL *curl = NULL;
|
||||
@ -468,7 +551,7 @@ void fetch_weather_info(location *curloc)
|
||||
timed_thread_unlock(curloc->p_timed_thread);
|
||||
free(chunk.memory);
|
||||
} else {
|
||||
ERR("No data from server");
|
||||
ERR("weather: no data from server");
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
@ -485,12 +568,12 @@ void init_thread(location *curloc, int interval)
|
||||
timed_thread_create(&weather_thread,
|
||||
(void *)curloc, interval * 1000000);
|
||||
if (!curloc->p_timed_thread) {
|
||||
ERR("Error creating weather timed thread");
|
||||
ERR("weather: error creating timed thread");
|
||||
}
|
||||
timed_thread_register(curloc->p_timed_thread,
|
||||
&curloc->p_timed_thread);
|
||||
if (timed_thread_run(curloc->p_timed_thread)) {
|
||||
ERR("Error running weather timed thread");
|
||||
ERR("weather: error running timed thread");
|
||||
}
|
||||
}
|
||||
|
||||
@ -507,14 +590,15 @@ void process_weather_info(char *p, int p_max_size, char *uri, char *data_type, i
|
||||
location *curloc = find_location(uri);
|
||||
if (!curloc->p_timed_thread) init_thread(curloc, interval);
|
||||
|
||||
|
||||
timed_thread_lock(curloc->p_timed_thread);
|
||||
if (strcmp(data_type, "last_update") == EQUAL) {
|
||||
strncpy(p, curloc->data.lastupd, p_max_size);
|
||||
} else if (strcmp(data_type, "temperature") == EQUAL) {
|
||||
temp_print(p, p_max_size, curloc->data.temp, TEMP_CELSIUS);
|
||||
} else if (strcmp(data_type, "cloud_cover") == EQUAL) {
|
||||
if (curloc->data.cc == 0) {
|
||||
if (curloc->data.xoap_t[0] != '\0') {
|
||||
strncpy(p, curloc->data.xoap_t, p_max_size);
|
||||
} else if (curloc->data.cc == 0) {
|
||||
strncpy(p, "", p_max_size);
|
||||
} else if (curloc->data.cc < 3) {
|
||||
strncpy(p, "clear", p_max_size);
|
||||
@ -575,6 +659,7 @@ void process_weather_info(char *p, int p_max_size, char *uri, char *data_type, i
|
||||
} else if (strcmp(data_type, "weather") == EQUAL) {
|
||||
strncpy(p, wc[curloc->data.wc], p_max_size);
|
||||
}
|
||||
|
||||
timed_thread_unlock(curloc->p_timed_thread);
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,8 @@
|
||||
|
||||
/* WEATHER data */
|
||||
typedef struct PWEATHER_ {
|
||||
char lastupd[17];
|
||||
char lastupd[32];
|
||||
char xoap_t[32];
|
||||
int temp;
|
||||
int dew;
|
||||
int cc;
|
||||
@ -39,6 +40,16 @@ typedef struct PWEATHER_ {
|
||||
int wind_d;
|
||||
int hmid;
|
||||
int wc;
|
||||
/*
|
||||
* TODO:
|
||||
* Is it worth investigating about using icons from weather.com?
|
||||
* We could use them for data from noaa as well.
|
||||
* They can display nicely with cimlib_add_image (with appropriate
|
||||
* #ifdefs on imlib2 and x11), and an additional input argoment for position.
|
||||
|
||||
char icon[3];
|
||||
|
||||
*/
|
||||
} PWEATHER;
|
||||
|
||||
/* Prototypes */
|
||||
|
Loading…
Reference in New Issue
Block a user