Mercurial > ~darius > hgwebdir.cgi > wh1080
view yreport.c @ 3:dc5ff2a1ed81
Be smarter about retries.
If the interrupt endpoint can't be read 100 times then retry the whole request.
author | Daniel O'Connor <darius@dons.net.au> |
---|---|
date | Wed, 10 Feb 2010 11:33:27 +1030 |
parents | 9da35e705144 |
children |
line wrap: on
line source
/* * 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 <stdlib.h> #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; }