view xreport.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: xreport.c,v 1.3 2010/02/07 03:41:35 grog Exp $
 */

#include "wh1080.h"

#define STAMPSIZE 32                            /* size of time stamp to print out */

struct readings current_readings;               /* current data readings, our version */
char reporturl [2048];                          /* build up report here */
time_t last_report;                             /* time of last report */

/*
 * 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;

/*
 * Update the last report time.
 */
void update_lastreport (time_t time)
{
  char report_time [STAMPSIZE];

  strftime (report_time,                        /* format time and date */
            STAMPSIZE,
            "%Y-%m-%d %T",
            localtime (&time));
  sprintf (mysql_querytext,
           "REPLACE INTO lastreport (station_id, report_id, date)\n"
           "VALUES (\"%s\", \"Wunderground\", \"%s\")",
           config.wunderground_station_id,
           report_time );
  doquery (mysql_querytext);
}

/*
 * Send information to Wunderground.
 *
 * See http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol for details
 * of communication protocol.
 *
 * Wunderground requires all values in archaic units, but pressures converted to
 * in Hg are converted back about 0.2 hPa too low.  We use a different
 * definition, which may or may not get the in Hg right, but results in correct
 * conversion back to hPa.
 *
 * Return 0 on success, 1 on failure.  Failure will be retried at the next
 * reporting interval.
 */

int really_inform_wunderground (time_t start, time_t end)
{
  /* Care: we can't add start and end, because they'll overflow */
  time_t midtime = start / 2 + end / 2;         /* average time of the interval  */
  char dateutc [STAMPSIZE];
  int something = 0;                            /* set when we find something to report */
  int i;                                        /* counter */

  /* Values to report */
  float inside_humidity;
  float inside_temp;
#if 0
  float inside_dewpoint;                        /* not currently used */
#endif
  float outside_humidity;
  float outside_temp;
  float outside_dewpoint;
  float pressure_msl;
  float wind_speed;
  float wind_gust;
  float wind_direction;
  float rain;

  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"
           "FROM observations\n"
           "WHERE unix_timestamp(timestamp(date,time)) >= %d\n"
           "  AND unix_timestamp(timestamp(date, time)) <= %d\n"
           "  AND station_id = \"%s\"\n",
           start,
           end,
           config.station_id );

  if (doquery (mysql_querytext))
    return 1;                                   /* failed and reported */

  if (verbose)
  {
    strftime (dateutc,                          /* format time and date */
              STAMPSIZE,
              "%Y-%m-%d %T",
              localtime (&start));
    printf ("Start date:\t\t%17s\n", dateutc);
    strftime (dateutc,                          /* format time and date */
              STAMPSIZE,
              "%Y-%m-%d %T",
              localtime (&end));
    printf ("End date:\t\t%17s\n", dateutc);
  }

  if (mysql_row = mysql_fetch_row (mysql_result)) /* got something */
  {
#if 0
    /*
     * What a mess!  The result of the query in in text form, and we need to convert it to float
     * both to reformat it and to convert units.
     */
    printf ("%s %s %s %s %s %s %s %s %s %s %s\n",
            mysql_row [0],
            mysql_row [1],
            mysql_row [2],
            mysql_row [3],
            mysql_row [4],
            mysql_row [5],
            mysql_row [6],
            mysql_row [7],
            mysql_row [8],
            mysql_row [9],
            mysql_row [10] );
#endif
    /*
     * Any of these values may be NULL.  If they all are, we don't have any data, so
     * wait for some to show up.
     */
    for (i = 0; i < 11; i++)
      if (mysql_row [i])
        something = 1;
    if (! something)                            /* nothing to report */
      return 1;                                 /* consider a "failure" */

    strftime (dateutc, STAMPSIZE, "%F+%H%%3a%M%%3a%S", gmtime (&midtime)); /* format time and date */

    /* Start building up the message */
    sprintf (reporturl,
             "./wundersend  "
             "'http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php"
             "?ID=%s&PASSWORD=%s"
             "&dateutc=%s",
             config.wunderground_station_id,
             config.wunderground_passwd,
             dateutc );

    /* Now find what we have to report */
    if (mysql_row [0])
    {
      inside_humidity = atof (mysql_row [0]);
      if (verbose)
        printf ("Inside humidity:\t%4.0f%%\n", inside_humidity);
      sprintf (&reporturl [strlen (reporturl)],
               "&indoorhumidity=%1.0f",
               inside_humidity );
    }
    if (mysql_row [1])
    {
      inside_temp = atof (mysql_row [1]);
      if (verbose)
        printf ("Inside temperature:\t%6.1f°\n", inside_temp);
      inside_temp = C_TO_F (inside_temp);
      sprintf (&reporturl [strlen (reporturl)],
               "&indoortempf=%2.1f",
               inside_temp );
    }
    /* mysql_row [2] is inside dewpoint, which we don't seem to be able to report */
    if (mysql_row [3])
    {
      outside_humidity = atof (mysql_row [3]);
      if (verbose)
        printf ("Outside humidity:\t%4.0f%%\n", outside_humidity);
      sprintf (&reporturl [strlen (reporturl)],
               "&humidity=%1.0f",
               outside_humidity );
    }
    if (mysql_row [4])
    {
      outside_temp = atof (mysql_row [4]);
      if (verbose)
        printf ("Outside temperature:\t%6.1f°\n", outside_temp);
      outside_temp = C_TO_F (atof (mysql_row [4]));
      sprintf (&reporturl [strlen (reporturl)],
               "&tempf=%2.1f",
               outside_temp );
    }
    if (mysql_row [5])
    {
      outside_dewpoint = atof (mysql_row [5]);
      if (verbose)
        printf ("Outside dewpoint:\t%6.1f°\n", outside_dewpoint);
      outside_dewpoint = C_TO_F (outside_dewpoint);
      sprintf (&reporturl [strlen (reporturl)],
               "&dewptf=%2.1f",
               outside_dewpoint );
    }
    if (mysql_row [6])
    {
      pressure_msl = atof (mysql_row [6]);
      if (verbose)
        printf ("Sea level pressure:\t%6.1f hPa\n", pressure_msl);
      pressure_msl *= Wunder_hPa_TO_inHg;
      sprintf (&reporturl [strlen (reporturl)],
               "&baromin=%4.4f",
               pressure_msl );
    }
    if (mysql_row [7])
    {
      wind_speed = atof (mysql_row [7]);
      if (verbose)
        printf ("Wind speed:\t\t%6.1f km/h\n", wind_speed);
      wind_speed *= KM_TO_MILES;
      sprintf (&reporturl [strlen (reporturl)],
               "&windspeedmph=%2.1f",
               wind_speed );
    }
    if (mysql_row [8])
    {
      wind_gust = atof (mysql_row [8]);
      if (verbose)
        printf ("Wind gust:\t\t%6.1f km/h\n", wind_gust);
      wind_gust *= KM_TO_MILES;
      sprintf (&reporturl [strlen (reporturl)],
               "&windgustmph=%2.1f",
               wind_gust );
    }
    if (mysql_row [9])                          /* wind direction */
    {
      wind_direction = atof (mysql_row [9]);
      if (verbose)
        printf ("Wind dir:\t\t%4.0f°\n", wind_direction);
      sprintf (&reporturl [strlen (reporturl)],
               "&winddir=%1.0f",
               wind_direction );
    }
    mysql_free_result (mysql_result);

    /*
     * Now do the rain.  This is special because it has to be per hour.
     */
    start = end - SECSPERHOUR;
    sprintf (mysql_querytext,
             "SELECT SUM(rain)\n"
             "FROM observations\n"
             "WHERE unix_timestamp(timestamp(date,time)) >= %d\n"
             "  AND unix_timestamp(timestamp(date, time)) <= %d\n"
             "  AND station_id = \"%s\"\n",
             start,
             end,
             config.station_id );

    if (doquery (mysql_querytext) == 0)         /* succeeded */
    {
      if ((mysql_row = mysql_fetch_row (mysql_result)) /* got something */
          && mysql_row [0] )                    /* and it's not NULL, */
      {
        rain = atof (mysql_row [0]);
        if (verbose)
          printf ("Rain per hour:\t\t%6.1f mm\n", rain);
        rain *= MM_TO_IN;
        sprintf (&reporturl [strlen (reporturl)],
                 "&rainin=%2.1f",
                 rain );
      }
    }

    sprintf (&reporturl [strlen (reporturl)],
             "&softwaretype=dereel-weather&action=updateraw'" );
    if (verbose)
      printf ("\n");                            /* end out output line */
    if (debug)
      puts (reporturl);
    if (update)
      system (reporturl);
  }
  return 0;
}

void inform_wunderground ()
{
  time_t now;                                   /* and time now */

  sprintf (mysql_querytext,
           "SELECT unix_timestamp(date) FROM lastreport\n"
           "  WHERE station_id =\"%s\"\n"
           "  AND report_id = \"Wunderground\"",
           config.wunderground_station_id );

  if (doquery (mysql_querytext))              /* silently ignore errors */
    return;
  now = time (NULL);
  if (mysql_row = mysql_fetch_row (mysql_result)) /* got something */
    last_report = atoi (mysql_row [0]);
  else
    last_report = now - config.wunderground_report_interval;
  mysql_free_result (mysql_result);

  /*
   * Report in strict intervals.
   */
  while ((now - last_report) >= config.wunderground_report_interval)
  {
    if (really_inform_wunderground (last_report, last_report + config.wunderground_report_interval))
      return;                                 /* failure, we'll retry later */
    last_report += config.wunderground_report_interval;
    update_lastreport (last_report);
    now = time (NULL);                        /* time moves on */
  }
}

void usage (char *me)
{
  fprintf (stderr,
           "Usage: %s [-d] [-n] [-v] [station ID] [db user] [password] [db host] [database]\n",
           me);
  exit (1);
}

int main (int argc, char *argv [])
{
  time_t nextrun;
  time_t now;

  if (read_config (argc, argv) < 0)
    usage (argv [0]);

  if (! config.wunderground_station_id)
  {
    fprintf (stderr, "No wunderground station ID in config\n");
    exit (1);
  }

  while (1)
  {
    inform_wunderground ();
    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 = last_report + config.wunderground_report_interval; /* next time to run */
    now = time (NULL);
    sleep (nextrun - now);
  }
  return 0;
}