view 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 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 "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;
}