Mercurial > ~darius > hgwebdir.cgi > wh1080
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 } |