comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:9dab44dcb331
1 /*
2 * Report weather conditions to remote web sites.
3 *
4 * Greg Lehey, 14 December 2009
5 *
6 * $Id: xreport.c,v 1.3 2010/02/07 03:41:35 grog Exp $
7 */
8
9 #include "wh1080.h"
10
11 #define STAMPSIZE 32 /* size of time stamp to print out */
12
13 struct readings current_readings; /* current data readings, our version */
14 char reporturl [2048]; /* build up report here */
15 time_t last_report; /* time of last report */
16
17 /*
18 * Data returned by database query, in the form we want.
19 */
20 struct weather_query
21 {
22 float inside_humidity;
23 float inside_temp;
24 float inside_dewpoint;
25 float outside_humidity;
26 float outside_temp;
27 float outside_dewpoint;
28 float pressure_msl;
29 float wind_speed;
30 float wind_gust;
31 float wind_direction;
32 float rain;
33 } weather_query;
34
35 /*
36 * Update the last report time.
37 */
38 void update_lastreport (time_t time)
39 {
40 char report_time [STAMPSIZE];
41
42 strftime (report_time, /* format time and date */
43 STAMPSIZE,
44 "%Y-%m-%d %T",
45 localtime (&time));
46 sprintf (mysql_querytext,
47 "REPLACE INTO lastreport (station_id, report_id, date)\n"
48 "VALUES (\"%s\", \"Wunderground\", \"%s\")",
49 config.wunderground_station_id,
50 report_time );
51 doquery (mysql_querytext);
52 }
53
54 /*
55 * Send information to Wunderground.
56 *
57 * See http://wiki.wunderground.com/index.php/PWS_-_Upload_Protocol for details
58 * of communication protocol.
59 *
60 * Wunderground requires all values in archaic units, but pressures converted to
61 * in Hg are converted back about 0.2 hPa too low. We use a different
62 * definition, which may or may not get the in Hg right, but results in correct
63 * conversion back to hPa.
64 *
65 * Return 0 on success, 1 on failure. Failure will be retried at the next
66 * reporting interval.
67 */
68
69 int really_inform_wunderground (time_t start, time_t end)
70 {
71 /* Care: we can't add start and end, because they'll overflow */
72 time_t midtime = start / 2 + end / 2; /* average time of the interval */
73 char dateutc [STAMPSIZE];
74 int something = 0; /* set when we find something to report */
75 int i; /* counter */
76
77 /* Values to report */
78 float inside_humidity;
79 float inside_temp;
80 #if 0
81 float inside_dewpoint; /* not currently used */
82 #endif
83 float outside_humidity;
84 float outside_temp;
85 float outside_dewpoint;
86 float pressure_msl;
87 float wind_speed;
88 float wind_gust;
89 float wind_direction;
90 float rain;
91
92 sprintf (mysql_querytext,
93 "SELECT AVG(inside_humidity),\n"
94 " AVG(inside_temp),\n"
95 " AVG(inside_dewpoint),\n"
96 " AVG(outside_humidity),\n"
97 " AVG(outside_temp),\n"
98 " AVG(outside_dewpoint),\n"
99 " AVG(pressure_msl),\n"
100 " AVG(wind_speed),\n"
101 " AVG(wind_gust),\n"
102 " AVG(wind_direction)\n"
103 "FROM observations\n"
104 "WHERE unix_timestamp(timestamp(date,time)) >= %d\n"
105 " AND unix_timestamp(timestamp(date, time)) <= %d\n"
106 " AND station_id = \"%s\"\n",
107 start,
108 end,
109 config.station_id );
110
111 if (doquery (mysql_querytext))
112 return 1; /* failed and reported */
113
114 if (verbose)
115 {
116 strftime (dateutc, /* format time and date */
117 STAMPSIZE,
118 "%Y-%m-%d %T",
119 localtime (&start));
120 printf ("Start date:\t\t%17s\n", dateutc);
121 strftime (dateutc, /* format time and date */
122 STAMPSIZE,
123 "%Y-%m-%d %T",
124 localtime (&end));
125 printf ("End date:\t\t%17s\n", dateutc);
126 }
127
128 if (mysql_row = mysql_fetch_row (mysql_result)) /* got something */
129 {
130 #if 0
131 /*
132 * What a mess! The result of the query in in text form, and we need to convert it to float
133 * both to reformat it and to convert units.
134 */
135 printf ("%s %s %s %s %s %s %s %s %s %s %s\n",
136 mysql_row [0],
137 mysql_row [1],
138 mysql_row [2],
139 mysql_row [3],
140 mysql_row [4],
141 mysql_row [5],
142 mysql_row [6],
143 mysql_row [7],
144 mysql_row [8],
145 mysql_row [9],
146 mysql_row [10] );
147 #endif
148 /*
149 * Any of these values may be NULL. If they all are, we don't have any data, so
150 * wait for some to show up.
151 */
152 for (i = 0; i < 11; i++)
153 if (mysql_row [i])
154 something = 1;
155 if (! something) /* nothing to report */
156 return 1; /* consider a "failure" */
157
158 strftime (dateutc, STAMPSIZE, "%F+%H%%3a%M%%3a%S", gmtime (&midtime)); /* format time and date */
159
160 /* Start building up the message */
161 sprintf (reporturl,
162 "./wundersend "
163 "'http://weatherstation.wunderground.com/weatherstation/updateweatherstation.php"
164 "?ID=%s&PASSWORD=%s"
165 "&dateutc=%s",
166 config.wunderground_station_id,
167 config.wunderground_passwd,
168 dateutc );
169
170 /* Now find what we have to report */
171 if (mysql_row [0])
172 {
173 inside_humidity = atof (mysql_row [0]);
174 if (verbose)
175 printf ("Inside humidity:\t%4.0f%%\n", inside_humidity);
176 sprintf (&reporturl [strlen (reporturl)],
177 "&indoorhumidity=%1.0f",
178 inside_humidity );
179 }
180 if (mysql_row [1])
181 {
182 inside_temp = atof (mysql_row [1]);
183 if (verbose)
184 printf ("Inside temperature:\t%6.1f°\n", inside_temp);
185 inside_temp = C_TO_F (inside_temp);
186 sprintf (&reporturl [strlen (reporturl)],
187 "&indoortempf=%2.1f",
188 inside_temp );
189 }
190 /* mysql_row [2] is inside dewpoint, which we don't seem to be able to report */
191 if (mysql_row [3])
192 {
193 outside_humidity = atof (mysql_row [3]);
194 if (verbose)
195 printf ("Outside humidity:\t%4.0f%%\n", outside_humidity);
196 sprintf (&reporturl [strlen (reporturl)],
197 "&humidity=%1.0f",
198 outside_humidity );
199 }
200 if (mysql_row [4])
201 {
202 outside_temp = atof (mysql_row [4]);
203 if (verbose)
204 printf ("Outside temperature:\t%6.1f°\n", outside_temp);
205 outside_temp = C_TO_F (atof (mysql_row [4]));
206 sprintf (&reporturl [strlen (reporturl)],
207 "&tempf=%2.1f",
208 outside_temp );
209 }
210 if (mysql_row [5])
211 {
212 outside_dewpoint = atof (mysql_row [5]);
213 if (verbose)
214 printf ("Outside dewpoint:\t%6.1f°\n", outside_dewpoint);
215 outside_dewpoint = C_TO_F (outside_dewpoint);
216 sprintf (&reporturl [strlen (reporturl)],
217 "&dewptf=%2.1f",
218 outside_dewpoint );
219 }
220 if (mysql_row [6])
221 {
222 pressure_msl = atof (mysql_row [6]);
223 if (verbose)
224 printf ("Sea level pressure:\t%6.1f hPa\n", pressure_msl);
225 pressure_msl *= Wunder_hPa_TO_inHg;
226 sprintf (&reporturl [strlen (reporturl)],
227 "&baromin=%4.4f",
228 pressure_msl );
229 }
230 if (mysql_row [7])
231 {
232 wind_speed = atof (mysql_row [7]);
233 if (verbose)
234 printf ("Wind speed:\t\t%6.1f km/h\n", wind_speed);
235 wind_speed *= KM_TO_MILES;
236 sprintf (&reporturl [strlen (reporturl)],
237 "&windspeedmph=%2.1f",
238 wind_speed );
239 }
240 if (mysql_row [8])
241 {
242 wind_gust = atof (mysql_row [8]);
243 if (verbose)
244 printf ("Wind gust:\t\t%6.1f km/h\n", wind_gust);
245 wind_gust *= KM_TO_MILES;
246 sprintf (&reporturl [strlen (reporturl)],
247 "&windgustmph=%2.1f",
248 wind_gust );
249 }
250 if (mysql_row [9]) /* wind direction */
251 {
252 wind_direction = atof (mysql_row [9]);
253 if (verbose)
254 printf ("Wind dir:\t\t%4.0f°\n", wind_direction);
255 sprintf (&reporturl [strlen (reporturl)],
256 "&winddir=%1.0f",
257 wind_direction );
258 }
259 mysql_free_result (mysql_result);
260
261 /*
262 * Now do the rain. This is special because it has to be per hour.
263 */
264 start = end - SECSPERHOUR;
265 sprintf (mysql_querytext,
266 "SELECT SUM(rain)\n"
267 "FROM observations\n"
268 "WHERE unix_timestamp(timestamp(date,time)) >= %d\n"
269 " AND unix_timestamp(timestamp(date, time)) <= %d\n"
270 " AND station_id = \"%s\"\n",
271 start,
272 end,
273 config.station_id );
274
275 if (doquery (mysql_querytext) == 0) /* succeeded */
276 {
277 if ((mysql_row = mysql_fetch_row (mysql_result)) /* got something */
278 && mysql_row [0] ) /* and it's not NULL, */
279 {
280 rain = atof (mysql_row [0]);
281 if (verbose)
282 printf ("Rain per hour:\t\t%6.1f mm\n", rain);
283 rain *= MM_TO_IN;
284 sprintf (&reporturl [strlen (reporturl)],
285 "&rainin=%2.1f",
286 rain );
287 }
288 }
289
290 sprintf (&reporturl [strlen (reporturl)],
291 "&softwaretype=dereel-weather&action=updateraw'" );
292 if (verbose)
293 printf ("\n"); /* end out output line */
294 if (debug)
295 puts (reporturl);
296 if (update)
297 system (reporturl);
298 }
299 return 0;
300 }
301
302 void inform_wunderground ()
303 {
304 time_t now; /* and time now */
305
306 sprintf (mysql_querytext,
307 "SELECT unix_timestamp(date) FROM lastreport\n"
308 " WHERE station_id =\"%s\"\n"
309 " AND report_id = \"Wunderground\"",
310 config.wunderground_station_id );
311
312 if (doquery (mysql_querytext)) /* silently ignore errors */
313 return;
314 now = time (NULL);
315 if (mysql_row = mysql_fetch_row (mysql_result)) /* got something */
316 last_report = atoi (mysql_row [0]);
317 else
318 last_report = now - config.wunderground_report_interval;
319 mysql_free_result (mysql_result);
320
321 /*
322 * Report in strict intervals.
323 */
324 while ((now - last_report) >= config.wunderground_report_interval)
325 {
326 if (really_inform_wunderground (last_report, last_report + config.wunderground_report_interval))
327 return; /* failure, we'll retry later */
328 last_report += config.wunderground_report_interval;
329 update_lastreport (last_report);
330 now = time (NULL); /* time moves on */
331 }
332 }
333
334 void usage (char *me)
335 {
336 fprintf (stderr,
337 "Usage: %s [-d] [-n] [-v] [station ID] [db user] [password] [db host] [database]\n",
338 me);
339 exit (1);
340 }
341
342 int main (int argc, char *argv [])
343 {
344 time_t nextrun;
345 time_t now;
346
347 if (read_config (argc, argv) < 0)
348 usage (argv [0]);
349
350 if (! config.wunderground_station_id)
351 {
352 fprintf (stderr, "No wunderground station ID in config\n");
353 exit (1);
354 }
355
356 while (1)
357 {
358 inform_wunderground ();
359 if (once) /* just run once */
360 exit (0);
361 /*
362 * Informing Wunderground takes finite time. Stay on schedule.
363 * We may end up off by a second from time to time, but we shouldn't drift.
364 *
365 */
366 nextrun = last_report + config.wunderground_report_interval; /* next time to run */
367 now = time (NULL);
368 sleep (nextrun - now);
369 }
370 return 0;
371 }