diff 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 diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/xreport.c	Tue Feb 09 13:44:25 2010 +1030
@@ -0,0 +1,371 @@
+/*
+ * 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;
+}