Mercurial > ~darius > hgwebdir.cgi > wh1080
diff yreport.c @ 0:9dab44dcb331
Initial commit of Greg's code from http://www.lemis.com/grog/tmp/wh1080.tar.gz
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Tue, 09 Feb 2010 13:44:25 +1030 |
parents | |
children | 9da35e705144 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/yreport.c Tue Feb 09 13:44:25 2010 +1030 @@ -0,0 +1,301 @@ +/* + * Report weather conditions to remote web sites. + * + * Greg Lehey, 14 December 2009 + * + * $Id: yreport.c,v 1.2 2010/02/07 03:39:12 grog Exp $ + */ + +#include "wh1080.h" + +#define STAMPSIZE 32 /* size of time stamp to print out */ + +/* + * Data returned by database query, in the form we want. + */ +struct weather_query +{ + float inside_humidity; + float inside_temp; + float inside_dewpoint; + float outside_humidity; + float outside_temp; + float outside_dewpoint; + float pressure_msl; + float wind_speed; + float wind_gust; + float wind_direction; + float rain; +} weather_query; + +/* Format strings for printing out variables */ +char *rowformat1 [] = {"\t$inside_humidity = %4.0f;\n", + "\t$inside_temperature = %2.1f;\n", + "\t$inside_dewpoint = %2.1f;\n", + "\t$outside_humidity = %4.0f;\n", + "\t$outside_temperature = %2.1f;\n", + "\t$outside_dewpoint = %2.1f;\n", + "\t$pressure_msl = %2.1f;\n", + "\t$wind_speed = %2.1f;\n", + "\t$wind_gust = %2.1f;\n", + "\t$wind_direction = %4.0f;\n", + "\t$rain = %2.1f;\n"}; + +char *rowformat2 [] = {"\t$max_inside_humidity = %2.3f;\n", + "\t$min_inside_humidity = %2.3f;\n", + "\t$max_inside_temp = %2.3f;\n", + "\t$min_inside_temp = %2.3f;\n", + "\t$max_inside_dewpoint = %2.3f;\n", + "\t$min_inside_dewpoint = %2.3f;\n", + "\t$max_outside_humidity = %2.3f;\n", + "\t$min_outside_humidity = %2.3f;\n", + "\t$max_outside_temp = %2.3f;\n", + "\t$min_outside_temp = %2.3f;\n", + "\t$max_outside_dewpoint = %2.3f;\n", + "\t$min_outside_dewpoint = %2.3f;\n", + "\t$max_pressure_msl = %2.3f;\n", + "\t$min_pressure_msl = %2.3f;\n", + "\t$max_wind_speed = %2.3f;\n", + "\t$min_wind_speed = %2.3f;\n", + "\t$max_wind_gust = %2.3f;\n", + "\t$min_wind_gust = %2.3f;\n", + "\t$sum_rain = %2.3f;\n" }; + +char *maxmintimes [] = {"inside_humidity", + "inside_temp", + "inside_dewpoint", + "outside_humidity", + "outside_temp", + "outside_dewpoint", + "pressure_msl", + "wind_speed", + "wind_gust" }; + +int rowformats1 = sizeof (rowformat1) / sizeof (char *); +int rowformats2 = sizeof (rowformat2) / sizeof (char *); +int maxmincount = sizeof (maxmintimes) / sizeof (char *); + +/* + * Create a header file for PHP pages. The "current readings" are an average + * over the last config.website_generation_interval seconds. + */ + +/* + * An alternative query method could be prepared statements. See + * http://dev.mysql.com/doc/refman/5.1/en/c-api-prepared-statements.html for + * details. Peter Jeremy says: "Search for MYSQL_BIND, mysql_stmt_bind_param() + * and mysql_stmt_bind_result()." + */ +void make_php_header_file () +{ + time_t start; + time_t now; + FILE *header_file; + char date_time [DATETEXTLENGTH]; /* Wednesday, 25 November 2009 16:47:46 */ + time_t yesterday; + char yesterday_text [DATETEXTLENGTH]; /* YYYY-MM-DD */ + int row; + int rough_direction; /* out of range */ + + header_file = fopen (config.php_header, "w"); + if (! header_file) + fprintf (stderr, + "Can't open %s: %s (%d)\n", + config.php_header, + strerror (errno), + errno ); + else + { + now = time (NULL); + start = now - config.website_generation_interval; /* determine the time we're doing this for */ + strftime (date_time, DATETEXTLENGTH, "%A, %e %B %Y %T", localtime (&now)); + yesterday = now - SECSPERDAY; /* this time yesterday */ + strftime (yesterday_text, DATETEXTLENGTH, "%F", localtime (&yesterday)); + + fprintf (header_file, + "<?php\n" + "/* Automatically generated file. Do not edit */\n" + "\t$timetext = \"%s\";\n" + "\t$yesterday = \"%s\";\n" + "\t$timestamp = %d;\n", + date_time, /* time in text form */ + yesterday_text, /* yesterday's date YYYY-MM-DD */ + (int) now ); /* time of reading */ + + sprintf (mysql_querytext, + "SELECT AVG(inside_humidity),\n" + " AVG(inside_temp),\n" + " AVG(inside_dewpoint),\n" + " AVG(outside_humidity),\n" + " AVG(outside_temp),\n" + " AVG(outside_dewpoint),\n" + " AVG(pressure_msl),\n" + " AVG(wind_speed),\n" + " AVG(wind_gust),\n" + " AVG(wind_direction),\n" + " SUM(rain)\n" + "FROM %s\n" + "WHERE unix_timestamp(timestamp(date,time)) >= %d\n" + " AND unix_timestamp(timestamp(date, time)) <= %d\n" + " AND station_id = \"%s\"\n", + config.db_table, + start, + now, + config.station_id ); + + if (doquery (mysql_querytext)) + return; /* failed and reported */ + + if (mysql_row = mysql_fetch_row (mysql_result)) /* got something */ + { + for (row = 0; row < rowformats1; row++) + { + /* + * We have a problem here: if a value is missing, we can't just print + * it. Fake a number for the time being. + */ + if (mysql_row [row] && *mysql_row [row]) /* something there */ + fprintf (header_file, rowformat1 [row], atof (mysql_row [row])); + else + fprintf (header_file, rowformat1 [row], -999.0); + } + + /* Isn't this ugly? */ + rough_direction = 1000; /* out of range */ + if ((mysql_row [9]) && (*mysql_row [9])) /* something there */ + rough_direction = (int) ((atof (mysql_row [9]) + 11.25) / 22.5); + + if ((rough_direction < 16) && (rough_direction >= 0)) + fprintf (header_file, + "\t$wind_direction_text = \"%s\";\n", + wind_directions [rough_direction] ) ; + else + fprintf (header_file, "\t$wind_direction_text = \"(none)\";\n"); + mysql_free_result (mysql_result); + } + + /* Now stats for the day */ + strftime (date_time, DATETEXTLENGTH, "%Y-%m-%d", localtime (&now)); + sprintf (mysql_querytext, + "SELECT @max_inside_humidity := MAX(inside_humidity),\n" + " @min_inside_humidity := MIN(inside_humidity),\n" + " @max_inside_temp := MAX(inside_temp),\n" + " @min_inside_temp := MIN(inside_temp),\n" + " @max_inside_dewpoint := MAX(inside_dewpoint),\n" + " @min_inside_dewpoint := MIN(inside_dewpoint),\n" + " @max_outside_humidity := MAX(outside_humidity),\n" + " @min_outside_humidity := MIN(outside_humidity),\n" + " @max_outside_temp := MAX(outside_temp),\n" + " @min_outside_temp := MIN(outside_temp),\n" + " @max_outside_dewpoint := MAX(outside_dewpoint),\n" + " @min_outside_dewpoint := MIN(outside_dewpoint),\n" + " @max_pressure_msl := MAX(pressure_msl),\n" + " @min_pressure_msl := MIN(pressure_msl),\n" + " @max_wind_speed := MAX(wind_speed),\n" + " @min_wind_speed := MIN(wind_speed),\n" + " @max_wind_gust := MAX(wind_gust),\n" + " @min_wind_gust := MIN(wind_gust),\n" + " SUM(rain)\n" + "FROM %s\n" + "WHERE date = \"%s\"\n" + " AND station_id = \"%s\"\n", + config.db_table, + date_time, + config.station_id ); + + if (doquery (mysql_querytext)) + return; /* failed and reported */ + + if (mysql_row = mysql_fetch_row (mysql_result)) /* got something */ + { + for (row = 0; row < rowformats2; row++) + fprintf (header_file, rowformat2 [row], atof (mysql_row [row])); + mysql_free_result (mysql_result); + } + + /* Now get the times that go with the maxima and minima */ + for (row = 0; row < maxmincount; row++) + { + /* Time of maximum */ + sprintf (mysql_querytext, + "SELECT time from %s\n" + "WHERE date = \"%s\"\n" + " AND station_id = \"%s\"\n" + " AND %s = @max_%s\n" + "LIMIT 1", + config.db_table, + date_time, + config.station_id, + maxmintimes [row], + maxmintimes [row] ); + if (doquery (mysql_querytext)) /* failure */ + return; /* XXX be cleverer */ + if (mysql_row = mysql_fetch_row (mysql_result)) /* got something */ + { + fprintf (header_file, "\t$max_%s_time = \"%s\";\n", maxmintimes [row], mysql_row [0]); + mysql_free_result (mysql_result); + } + else /* dummy */ + fprintf (header_file, "\t$max_%s_time = \"unknown\"\n", maxmintimes [row]); + /* Now time of minimum */ + sprintf (mysql_querytext, + "SELECT time from %s\n" + "WHERE date = \"%s\"\n" + " AND station_id = \"%s\"\n" + " AND %s = @min_%s\n" + "LIMIT 1", + config.db_table, + date_time, + config.station_id, + maxmintimes [row], + maxmintimes [row] ); + if (doquery (mysql_querytext)) /* failure */ + return; /* XXX be cleverer */ + if (mysql_row = mysql_fetch_row (mysql_result)) /* got something */ + { + fprintf (header_file, "\t$min_%s_time = \"%s\";\n", maxmintimes [row], mysql_row [0]); + mysql_free_result (mysql_result); + } + else /* dummy */ + fprintf (header_file, "\t$min_%s_time = \"unknown\"\n", maxmintimes [row]); + } + + fprintf (header_file, "\t?>\n"); /* end */ + fclose (header_file); + } +} + +void usage (char *me) +{ + fprintf (stderr, + "Usage: %s [-d] [-n] [-v] [-1] [station ID] [db user] [password] [db host] [database]\n", + me); + exit (1); +} + +int main (int argc, char *argv []) +{ + time_t lastrun; + time_t nextrun; + time_t now; + + if (read_config (argc, argv) < 0) + usage (argv [0]); + + while (1) + { + lastrun = time (NULL); /* time we ran the loop */ + make_php_header_file (); + if (once) /* just run once */ + exit (0); + /* + * Informing Wunderground takes finite time. Stay on schedule. + * We may end up off by a second from time to time, but we shouldn't drift. + * + */ + nextrun = lastrun + config.website_generation_interval; /* next time to run */ + now = time (NULL); + sleep (nextrun - now); + } + return 0; +}