Remove trailing whitespace.
[dockapps.git] / wmWeather / Src / wmWeather.c
blob5733de6828666254dd6c11fc47fb794cc5d87f77
1 /*
3 * wmWeather-1.31 (C) 1999 Mike Henderson (mghenderson@lanl.gov)
5 * - Shows Local Weather conditions
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2, or (at your option)
13 * any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program (see the file COPYING); if not, write to the
22 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
23 * Boston, MA 02110-1301 USA
28 * ToDo:
30 * - Add a GTK popup window to display data in a nicer way. Currently just use
31 * xmessage...
33 * - Add "current conditions" graphic (as background?). I.e. one of those little
34 * cartoons that show clouds or sun with rain or snow, etc. on it...
36 * - Scrolling line to display "sundry" parameters.
38 * - Or maybe auto-switch between panels at some user-defined rate?
41 * Changes:
43 * Version 1.31 - released May 4, 1999.
44 * fixed some conversion bugs in wind speed..
46 * Version 1.30 - released April 13, 1999.
47 * Fixed a bug whereby the App would crash when trying to gain input
48 * focus under non-WindowMaker WMs (focus is now grabbed by
49 * `PointerRoot' not `iconwin').
51 * Added StationID and `time-of-last-update' labels. To do this I needed
52 * to shrink the fonts down and scrunch them together a bit more.
54 * Added new command line option to change their color;
55 * -tc <color>
57 * Added code to properly decode wind speed when in MPS.
59 * Fixed bug in beaufort wind speed calcs.
61 * Version 1.29 - released March 17, 1999.
62 * Reorganized wmgeneral.c and renamed it xutils.c (wmgeneral.h
63 * -> xutils.h as well ). Also moved it into the same directory as wmWeather.
64 * Now, the openXwindow is split into 2 parts. You first need to call
65 * initXwindow(argc, argv). This allows us to check the display depth
66 * before we commit to a particular pixmap (this will be useful in my
67 * other DockApps to dynamically set appropriate pixmaps based on depth).
68 * Got rid of alot of the other routines that I never use.
70 * Added 4 more command line option to set the colors of the text:
72 * -bc <color> for setting the BackGround color.
73 * -lc <color> for setting the Label color.
74 * -dc <color> for setting the Data color.
75 * -wgc <color> for setting the Wind Gust color.
77 * Also cleaned up the pixmap to minimize the number of colors used.
79 * Changed metric toggle to work with a key press (any key).
81 * Added double click support. Now double clicking does the following:
83 * Double Mouse Left: pops up the fully decoded METAR file
84 * in xmessage.
86 * Double Mouse Middle: Currently undefined.
88 * Double Mouse Right: Forces a new update (i.e. download.)
91 * Version 1.28 - released March 9, 1999.
92 * Changed -celsius (-c) option to -metric (-m). Naming makes more
93 * sense that way...
95 * Added -W option to display WindChill instead of DewPoint.
96 * Since Windchill is not always available, we only show it if its
97 * available. If its not, we paste up DewPoint as default.
99 * Also added -mps option to display wind speed in units of
100 * meters/second (when in -metric mode).
102 * Version 1.27 - released March 8, 1999.
103 * fixed bug in speed calculation when wind is gusting.
105 * Version 1.26 - released February 24, 1999.
106 * Added -delay option.
108 * Version 1.25 - released February 16, 1999.
109 * Added Wind speeds on the 'Beaufort scale'
110 * Thanks to Paul Martin <pm@zetnet.net> for this addition.
112 * Version 1.24 - released February 12, 1999.
113 * Added --passive-ftp option to wget.
115 * Version 1.23 - released February 2, 1999.
116 * Few more bug fixes...
117 * Added support for different Pressure units...
120 * Version 1.22 - released February 1, 1999.
121 * Fixed minor bug in direction abbreviations. Added a bit more to man
122 * page.
124 * Version 1.21 - released January 29, 1999.
125 * Fixed a problem in the perl script. Made the file paths absolute.
127 * Version 1.2 - released January 29, 1999.
128 * Added Wind speed line. Ended up decoding the Raw METAR line.
129 * Fixed a few bugs...
130 * Changed location of files from /tmp to ~/.wmWeatherReports
131 * Changed units of pressure and wind speed to mmHg and km/h
132 * when Metric is set. (Really should change the flag to -metric).
134 * Version 1.1 - released January 25, 1999.
135 * Bug fixes...
136 * Added command line switch to display Temp's in deg. C
139 * Version 1.0 - released January 19, 1999.
149 * Includes
151 #include <stdio.h>
152 #include <unistd.h>
153 #include <stdlib.h>
154 #include <string.h>
155 #include <ctype.h>
156 #include <time.h>
157 #include <X11/X.h>
158 #include <X11/xpm.h>
159 #include "xutils.h"
160 #include "wmWeather_master.xpm"
161 #include "wmWeather_mask.xbm"
166 * Delay between refreshes (in microseconds)
168 #define DELAY 10000L
169 #define WMWEATHER_VERSION "1.31"
170 #define DEFAULT_UPDATEDELAY 900L
175 void ParseCMDLine(int argc, char *argv[]);
176 void ButtonPressEvent(XButtonEvent *);
177 void KeyPressEvent(XKeyEvent *);
178 char *StringToUpper(char *);
181 char StationID[10];
182 int UpToDate = 0;
183 int ShowWindChill = 0;
184 int WindChillAvail = 1;
185 int Metric = 0;
186 int Beaufort = 0;
187 int ForceUpdate = 1;
188 int ForceDownload = 1;
189 int PressureUnits = 0;
190 int MetersPerSecond = 0;
191 double PressureConv = 1.0;
192 long UpdateDelay;
193 int GotFirstClick1, GotDoubleClick1;
194 int GotFirstClick2, GotDoubleClick2;
195 int GotFirstClick3, GotDoubleClick3;
196 int DblClkDelay;
200 * In a more readable form the Compass directions are:
201 * static char *CompassDirection[] = { "N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE",
202 * "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"}
203 * We convert to digits in the sequence `NWSE' so we dont have to put all these
204 * combinations into the pixmap.
206 static char *CompassDirection[] = { "0", "003", "03", "303", "3", "323", "23", "223",
207 "2", "221", "21", "121", "1", "101", "01", "001"};
211 char LabelColor[30] = "#79bdbf";
212 char WindGustColor[30] = "#ff0000";
213 char DataColor[30] = "#ffbf50";
214 char BackColor[30] = "#181818";
215 char StationTimeColor[30] = "#c5a6ff";
220 * main
222 int main(int argc, char *argv[]) {
224 struct tm *tTime;
225 XEvent event;
226 int n, s, m, dt1, dt2, dt3, yd;
227 int i, j, len;
228 char dir[5];
229 int Year, Month, Day;
230 int Hours, Mins, Secs;
231 int UpdateLTHour = 0.0, UpdateLTMin = 0.0, UpdateUTHour, UpdateUTMin;
232 long CurrentLocalTime;
233 double UpdateUT, UpdateLT, UT, LT, DT, hour24();
236 double jd(), CurrentJD;
237 char command[1024], Line[512], FileName[10];
238 int Tens, q, digit, chr;
239 double Pressure, Temperature, sgn, Humidity, DewPoint, WindChill, val;
240 double Direction, Speed;
241 FILE *fp;
254 * Parse any command line arguments.
256 ParseCMDLine(argc, argv);
261 * Do the window opening in 2 stages. After the initXwindow() call,
262 * we know what the Depth of the Display is. We can then pick an appropriate
263 * XPM to use. I.e. may want to use one that has fewer colors to make the App work
264 * better on a low-color 8-bit display.
266 initXwindow(argc, argv);
267 openXwindow(argc, argv, wmWeather_master, wmWeather_mask_bits, wmWeather_mask_width,
268 wmWeather_mask_height, BackColor, LabelColor, WindGustColor, DataColor, StationTimeColor);
274 * Loop until we die
276 n = 32000;
277 s = 32000;
278 m = 32000;
279 dt1 = 32000;
280 dt2 = 32000;
281 dt3 = 32000;
282 DblClkDelay = 32000;
283 UpToDate = 0;
284 while(1) {
290 * Keep track of # of seconds
292 if (m > 100){
294 m = 0;
295 ++dt1;
296 ++dt2;
297 ++dt3;
299 } else {
302 * Increment counter
304 ++m;
314 * Double Click Delays
315 * Keep track of click events. If Delay too long, set GotFirstClick's to False.
317 if (DblClkDelay > 15) {
319 DblClkDelay = 0;
320 GotFirstClick1 = 0; GotDoubleClick1 = 0;
321 GotFirstClick2 = 0; GotDoubleClick2 = 0;
322 GotFirstClick3 = 0; GotDoubleClick3 = 0;
324 } else {
326 ++DblClkDelay;
342 * Process any pending X events.
344 while(XPending(display)){
345 XNextEvent(display, &event);
346 switch(event.type){
347 case Expose:
348 RedrawWindow();
349 break;
350 case ButtonPress:
351 ButtonPressEvent(&event.xbutton);
352 break;
353 case KeyPress:
354 KeyPressEvent(&event.xkey);
355 break;
356 case ButtonRelease:
357 break;
358 case EnterNotify:
359 XSetInputFocus(display, PointerRoot, RevertToParent, CurrentTime);
360 break;
361 case LeaveNotify:
362 XSetInputFocus(display, PointerRoot, RevertToParent, CurrentTime);
363 break;
376 * Check the Current Conditions file every (approx.) several seconds.
377 * Can significantly reduce this frequency later. But its
378 * easier to debug this way...
379 * Do this before trying to download again! The file may be there and it
380 * may be Up-To-Date!
382 if ((dt2 > 5)||(ForceUpdate)){
384 dt2 = 0;
387 * Compute Current Julian Date
389 CurrentLocalTime = time(CurrentTime);
390 tTime = gmtime(&CurrentLocalTime);
391 Year = tTime->tm_year+1900;
392 Month = tTime->tm_mon+1;
393 Day = tTime->tm_mday;
394 Hours = tTime->tm_hour;
395 Mins = tTime->tm_min;
396 Secs = tTime->tm_sec;
397 UT = (double)Hours + (double)Mins/60.0 + (double)Secs/3600.0;
398 CurrentJD = jd(Year, Month, Day, UT);
400 CurrentLocalTime = time(CurrentTime);
401 tTime = localtime(&CurrentLocalTime);
402 Year = tTime->tm_year+1900;
403 Month = tTime->tm_mon+1;
404 Day = tTime->tm_mday;
405 Hours = tTime->tm_hour;
406 Mins = tTime->tm_min;
407 Secs = tTime->tm_sec;
408 LT = (double)Hours + (double)Mins/60.0 + (double)Secs/3600.0;
410 DT = UT - LT;
411 if (DT > 24.0) DT -= 24.0;
412 if (DT < 0.00) DT += 24.0;
417 * Read in weather data
419 sprintf(FileName, "%s/.wmWeatherReports/%s.dat", getenv("HOME"), StationID);
420 if ((fp = fopen(FileName, "r")) != NULL){
422 fgets(Line, 512, fp);
423 fgets(Line, 512, fp);
424 fgets(Line, 512, fp);
425 fscanf(fp, "%d:%d", &UpdateUTHour, &UpdateUTMin);
426 if (UpdateUTHour != 99){
427 UpdateUT = UpdateUTHour + UpdateUTMin/60.0;
428 UpdateLT = UpdateUT - DT;
429 if (UpdateLT < 0.0) UpdateLT += 24.0;
430 if (UpdateLT > 24.0) UpdateLT -= 24.0;
431 UpdateLTHour = (int)UpdateLT;
432 UpdateLTMin = (int)((UpdateLT - (double)UpdateLTHour)*60.0 + 0.5);
433 if (UpdateLTMin >= 60){
434 ++UpdateLTHour;
435 if (UpdateLTHour >= 24) UpdateLTHour = 0;
436 UpdateLTMin = 0;
438 } else {
439 UpdateLTHour = 99;
440 UpdateLTMin = 99;
443 fscanf(fp, "%lf", &Temperature);
444 if (Metric) Temperature = (Temperature-32.0)*5.0/9.0;
445 fscanf(fp, "%lf", &DewPoint);
446 if (Metric) DewPoint = (DewPoint-32.0)*5.0/9.0;
448 fscanf(fp, "%lf", &WindChill);
450 * If WindChill is not available, revert to DewPoint
452 WindChillAvail = (WindChill < -900.0) ? 0 : 1;
453 if (Metric) WindChill = (WindChill-32.0)*5.0/9.0;
455 fscanf(fp, "%lf", &Pressure); Pressure += 0.005;
456 Pressure *= PressureConv;
457 fscanf(fp, "%lf", &Humidity);
458 fscanf(fp, "%lf", &Direction);
459 fscanf(fp, "%lf", &Speed);
460 if (Metric){
461 if (MetersPerSecond) Speed *= 0.4473;
462 else if (!Beaufort) Speed *= 1.609;
464 fclose(fp);
466 } else {
468 Temperature = -9999.0;
469 DewPoint = -9999.0;
470 WindChill = -9999.0;
471 Humidity = -9999.0;
472 Pressure = -9999.0;
473 Direction = -9999.0;
474 Speed = -9999.0;
489 * Draw window.
491 if ( (dt3 > 5) || ForceUpdate){
494 dt3 = 0;
499 * Clear window.
501 copyXPMArea(5, 69, 54, 54, 5, 5);
505 * Paste up Station ID and time of last update.
508 q = 0;
509 chr = (int)StationID[0] - 65; copyXPMArea(chr*5+2, 128, 5, 6, 7+q, 6); q+= 5;
510 chr = (int)StationID[1] - 65; copyXPMArea(chr*5+2, 128, 5, 6, 7+q, 6); q+= 5;
511 chr = (int)StationID[2] - 65; copyXPMArea(chr*5+2, 128, 5, 6, 7+q, 6); q+= 5;
512 chr = (int)StationID[3] - 65; copyXPMArea(chr*5+2, 128, 5, 6, 7+q, 6); q+= 5;
514 if (UpdateLTHour != 99){
515 q = 0;
516 Tens = (int)(UpdateLTHour);
517 copyXPMArea(Tens/10*5+2, 135, 5, 6, 36+q, 6); q+= 5;
518 copyXPMArea(Tens%10*5+2, 135, 5, 6, 36+q, 6); q+= 5;
519 copyXPMArea(53, 135, 1, 6, 36+q, 6); q+= 2;
520 Tens = (int)(UpdateLTMin);
521 copyXPMArea(Tens/10*5+2, 135, 5, 6, 36+q, 6); q+= 5;
522 copyXPMArea(Tens%10*5+2, 135, 5, 6, 36+q, 6); q+= 5;
534 * Paste up Temperature.
536 if ((Temperature > -999.0)&&(Temperature < 1000.0)){
537 sgn = (Temperature < 0.0) ? -1.0 : 1.0;
538 Temperature *= sgn;
539 Temperature = (double)((int)(Temperature + 0.5));
540 q = 0;
541 if (Temperature >= 100.0){
542 if (sgn < 0.0) { copyXPMArea(0*5+66, 35, 5, 6, 25, 15); q += 5; }
543 digit = (int)(Temperature/100.0);
544 copyXPMArea(digit*5+66, 57, 5, 6, 25+q, 15); q+= 5;
545 Tens = (int)(Temperature-digit*100.0);
546 copyXPMArea(Tens/10*5+66, 57, 5, 6, 25+q, 15); q+= 5;
547 copyXPMArea(Tens%10*5+66, 57, 5, 6, 25+q, 15); q+= 5;
548 } else {
549 if (sgn < 0.0) { copyXPMArea(0*5+66, 35, 5, 6, 25, 15); q += 5; }
550 Tens = (int)(Temperature);
551 if (Tens >= 10) { copyXPMArea(Tens/10*5+66, 57, 5, 6, 25+q, 15); q+= 5; }
552 copyXPMArea(Tens%10*5+66, 57, 5, 6, 25+q, 15); q+= 5;
554 if (Metric){
555 copyXPMArea(72, 34, 3, 3, 25+q, 14); q += 4;
556 copyXPMArea(81, 35, 4, 6, 25+q, 15);
557 } else {
558 copyXPMArea(72, 34, 8, 7, 25+q, 14);
569 * Paste up DewPoint or WindChill Temperature.
571 if (ShowWindChill && WindChillAvail){
572 val = WindChill;
573 copyXPMArea(66, 87, 17, 8, 5, 24);
574 } else {
575 val = DewPoint;
576 copyXPMArea(5, 87, 17, 8, 5, 24);
579 if ((val > -999.0)&&(val < 1000.0)){
580 sgn = (val < 0.0) ? -1.0 : 1.0;
581 val *= sgn;
582 val = (double)((int)(val + 0.5));
583 q = 0;
584 if (val >= 100.0){
585 if (sgn < 0.0) { copyXPMArea(0*5+66, 57, 5, 6, 25, 24); q += 5; }
586 digit = (int)(val/100.0);
587 copyXPMArea(digit*5+66, 57, 5, 6, 25+q, 24); q+= 5;
588 Tens = (int)(val-digit*100.0);
589 copyXPMArea(Tens/10*5+66, 57, 5, 6, 25+q, 24); q+= 5;
590 copyXPMArea(Tens%10*5+66, 57, 5, 6, 25+q, 24); q+= 5;
591 } else {
592 if (sgn < 0.0) { copyXPMArea(0*5+66, 35, 5, 6, 25, 24); q += 5; }
593 Tens = (int)(val);
594 if (Tens >= 10) { copyXPMArea(Tens/10*5+66, 57, 5, 6, 25+q, 24); q+= 5; }
595 copyXPMArea(Tens%10*5+66, 57, 5, 6, 25+q, 24); q+= 5;
597 if (Metric){
598 copyXPMArea(72, 34, 3, 3, 25+q, 23); q += 4;
599 copyXPMArea(81, 35, 4, 6, 25+q, 24);
600 } else {
601 copyXPMArea(72, 34, 8, 7, 25+q, 23);
614 * Paste up Pressure.
616 q = 0; s= 0;
617 if ((Pressure > 0.0)&&(Pressure <= 10000.0)){
618 val = Pressure;
620 digit = (int)(val/1000.0);
621 if (digit > 0) { copyXPMArea(digit*5+66, 57, 5, 6, 25+q, 33); q += 5; }
622 val -= (double)digit*1000;
624 digit = (int)(val/100.0);
625 if ((digit > 0)||(Pressure > 999.0)) { copyXPMArea(digit*5+66, 57, 5, 6, 25+q, 33); q += 5; }
626 val -= (double)digit*100;
628 digit = (int)(val/10.0);
629 if ((digit > 0)||(Pressure > 99.0)) { copyXPMArea(digit*5+66, 57, 5, 6, 25+q, 33); q += 5; }
630 val -= (double)digit*10;
632 digit = (int)val;
633 copyXPMArea(digit*5+66, 57, 5, 6, 25+q, 33); q += 5;
634 val -= (double)digit;
637 if ((PressureUnits != 2)||(!Metric)){
639 copyXPMArea(10*5+66+1, 57, 4, 6, 25+q, 33); q += 4;
641 val *= 10; digit = (int)val;
642 copyXPMArea(digit*5+66, 57, 5, 6, 25+q, 33); q += 5;
643 val -= (double)digit;
645 if (!Metric){
646 val *= 10; digit = (int)val;
647 copyXPMArea(digit*5+66, 57, 5, 6, 25+q, 33); q += 5;
648 /* val -= (double)digit; */
662 * Paste up Humidity.
664 q = 0;
665 if ((Humidity > -999.0)&&(Humidity <= 100.0)){
666 if (Humidity == 100.0){
667 copyXPMArea(1*5+66, 57, 5, 6, 25+q, 42); q += 5;
668 copyXPMArea(0*5+66, 57, 5, 6, 25+q, 42); q += 5;
669 copyXPMArea(0*5+66, 57, 5, 6, 25+q, 42); q += 5;
670 } else {
671 Tens = (int)(Humidity);
672 if (Tens >= 10) { copyXPMArea(Tens/10*5+66, 57, 5, 6, 25+q, 42); q += 5; }
673 copyXPMArea(Tens%10*5+66, 57, 5, 6, 25+q, 42); q += 5;
675 copyXPMArea(121, 57, 5, 6, 25+q, 42);
687 * Paste up Wind Info.
689 if ((Direction == 0.0)&&(Speed == 0.0)){
692 * Just write out `Calm' if both values are 0
694 copyXPMArea(66, 4, 23, 7, 25, 51);
696 } else {
699 * If the Direction < 0 this means that there was a "Wind direction
700 * Variability Group" found in the METAR code. I.e. Direction is variable.
701 * I think value should be the average. In any case flag it by making it a
702 * different color.
704 * Likewise, if Speed < 0, this means that a "Gusty" modifier was found
705 * in the RAW METAR code, and the value is only the average of the low
706 * and high values given. Again, flag it in a different color...
709 if ((Direction >= -360.0)&&(Direction <= 360.0)){
710 sgn = (Direction < 0.0) ? -1.0 : 1.0;
711 yd = (sgn < 0.0) ? 50 : 43;
712 Direction *= sgn;
713 q = 0;
714 i = (int)(Direction/360.0*16.0 + 0.5);
715 if (i>15) i = 0;
716 strcpy(dir, CompassDirection[i]);
717 len = strlen(dir);
718 for (j=0; j<len; ++j){
719 digit = (int)dir[j] - 48;
720 copyXPMArea(digit*5+66, yd, 5, 6, 25+q, 51); q+= 5;
722 q += 2;
723 } else if (Direction > 0.0){
726 * In this case, the wind direction is variable with speed < 6 Knots.
727 * A numerical direction is not given in these cases. Just write out 'VRB'.
729 q = 0;
730 copyXPMArea(4*5+66, 43, 5, 6, 25+q, 51); q+= 5;
731 copyXPMArea(5*5+66, 43, 5, 6, 25+q, 51); q+= 5;
732 copyXPMArea(6*5+66, 43, 5, 6, 25+q, 51); q+= 9;
735 if (Metric && Beaufort) {
736 int beau = 0;
737 int spd;
739 sgn = (Speed < 0.0) ? -1.0 : 1.0;
740 spd = (int)(sgn * (int)Speed);
741 if (spd > 1) { beau = 1; }
742 if (spd > 3) { beau = 2; }
743 if (spd > 4) { beau = 3; }
744 if (spd > 10) { beau = 4; }
745 if (spd > 16) { beau = 5; }
746 if (spd > 21) { beau = 6; }
747 if (spd > 27) { beau = 7; }
748 if (spd > 33) { beau = 8; }
749 if (spd > 40) { beau = 9; }
750 if (spd > 47) { beau = 10; }
751 if (spd > 55) { beau = 11; }
752 if (spd > 63) { beau = 12; }
753 if (spd > 71) { beau = 13; }
754 Speed = sgn * (double) beau;
755 q++; copyXPMArea(76, 35, 4, 6, 25+q, 51); q+= 6;
759 if ((Speed > -999.0)&&(Speed < 1000.0)){
760 sgn = (Speed < 0.0) ? -1.0 : 1.0;
761 yd = (sgn < 0.0) ? 64 : 57;
762 Speed *= sgn;
763 if (Speed >= 100.0){
764 digit = (int)(Speed/100.0);
765 copyXPMArea(digit*5+66, yd, 5, 6, 25+q, 51); q+= 5;
766 Tens = (int)(Speed-digit*100.0);
767 copyXPMArea(Tens/10*5+66, yd, 5, 6, 25+q, 51); q+= 5;
768 copyXPMArea(Tens%10*5+66, yd, 5, 6, 25+q, 51); q+= 5;
769 } else {
770 Tens = (int)(Speed);
771 if (Tens >= 10) { copyXPMArea(Tens/10*5+66, yd, 5, 6, 25+q, 51); q+= 5; }
772 copyXPMArea(Tens%10*5+66, yd, 5, 6, 25+q, 51); q+= 5;
786 * Make changes visible
788 RedrawWindow();
797 * Reset "force update" flag
799 ForceUpdate = 0;
805 * Check every 5 min if the values are not up to date...
808 * We still need to add a flashing LED to warn about
809 * times that are out of date. Also need to determine if it is uptodate...
811 UpToDate = 0;
812 if (((!UpToDate)&&(dt1 > UpdateDelay)) || ForceDownload){
814 dt1 = 0;
817 * Execute Perl script to grab the Latest METAR Report
819 sprintf(command, "GrabWeather %s &", StationID);
820 system(command);
822 ForceDownload = 0;
823 ForceUpdate = 1;
832 * Wait for next update
834 usleep(DELAY);
846 * ParseCMDLine()
848 void ParseCMDLine(int argc, char *argv[]) {
850 int i;
851 void print_usage();
853 StationID[0] = '\0';
854 PressureUnits = 0;
855 MetersPerSecond = 0;
856 ShowWindChill = 0;
857 UpdateDelay = DEFAULT_UPDATEDELAY;
858 for (i = 1; i < argc; i++) {
860 if (!strcmp(argv[i], "-display")){
862 ++i;
864 } else if (!strcmp(argv[i], "-bc")){
866 if ((i+1 >= argc)||(argv[i+1][0] == '-')) {
867 fprintf(stderr, "wmWeather: No color found\n");
868 print_usage();
869 exit(-1);
871 strcpy(BackColor, argv[++i]);
873 } else if (!strcmp(argv[i], "-tc")){
875 if ((i+1 >= argc)||(argv[i+1][0] == '-')) {
876 fprintf(stderr, "wmWeather: No color found\n");
877 print_usage();
878 exit(-1);
880 strcpy(StationTimeColor, argv[++i]);
882 } else if (!strcmp(argv[i], "-lc")){
884 if ((i+1 >= argc)||(argv[i+1][0] == '-')) {
885 fprintf(stderr, "wmWeather: No color found\n");
886 print_usage();
887 exit(-1);
889 strcpy(LabelColor, argv[++i]);
891 } else if (!strcmp(argv[i], "-wgc")){
893 if ((i+1 >= argc)||(argv[i+1][0] == '-')) {
894 fprintf(stderr, "wmWeather: No color found\n");
895 print_usage();
896 exit(-1);
898 strcpy(WindGustColor, argv[++i]);
900 } else if (!strcmp(argv[i], "-dc")){
902 if ((i+1 >= argc)||(argv[i+1][0] == '-')) {
903 fprintf(stderr, "wmWeather: No color found\n");
904 print_usage();
905 exit(-1);
907 strcpy(DataColor, argv[++i]);
909 } else if (!strcmp(argv[i], "-beaufort")){
911 Beaufort = 1;
913 } else if (!strcmp(argv[i], "-mps")){
915 MetersPerSecond = 1;
917 } else if (!strcmp(argv[i], "-W")){
919 ShowWindChill = 1;
921 } else if ((!strcmp(argv[i], "-metric"))||(!strcmp(argv[i], "-m"))){
923 Metric = 1;
925 } else if (!strcmp(argv[i], "-kPa")){
927 PressureUnits = 1;
928 PressureConv = 3.38639;
930 } else if (!strcmp(argv[i], "-hPa")){
932 PressureUnits = 2;
933 PressureConv = 33.8639;
935 } else if (!strcmp(argv[i], "-mmHg")){
937 PressureUnits = 3;
938 PressureConv = 25.4;
940 } else if ((!strcmp(argv[i], "-station"))||(!strcmp(argv[i], "-s"))){
942 if ((i+1 >= argc)||(argv[i+1][0] == '-')) {
943 fprintf(stderr, "wmWeather: No METAR station ID found\n");
944 print_usage();
945 exit(-1);
947 strcpy(StationID, StringToUpper(argv[++i]));
949 } else if (!strcmp(argv[i], "-delay")) {
951 if( (i+1 >= argc)||(argv[i+1][0] == '-')) {
953 fprintf(stderr,"You must give a time with the -delay option.\n");
954 print_usage();
955 exit(-1);
957 } else if(sscanf(argv[i+1], "%ld", &UpdateDelay) != 1) {
959 fprintf(stderr,"Dont understand the delay time you have entered (%s).\n", argv[i+1]);
960 print_usage();
961 exit(-1);
965 * Convert Time to seconds
967 UpdateDelay *= 60;
968 ++i;
970 } else {
972 print_usage();
973 exit(-11);
978 if (StationID[0] == '\0') {
979 fprintf(stderr, "\nwmWeather: You must specify a METAR station code\n\n");
980 print_usage();
981 exit(1);
984 if ((Metric)&&(PressureUnits == 0)){
985 PressureUnits = 3;
986 PressureConv = 25.4;
989 if (!Metric){
990 PressureConv = 1.0;
993 if (Beaufort && MetersPerSecond){
994 fprintf(stderr, "\nwmWeather: You cant use both -beaufort and -mps together.\n\n");
995 print_usage();
996 exit(1);
1002 void print_usage(){
1004 printf("\nwmWeather version: %s\n", WMWEATHER_VERSION);
1005 printf("\nusage: wmWeather -s <StationID> [-display <Display>] [-h] [-metric] [-kPa] [-hPa] [-mmHg]\n");
1006 printf(" [-beaufort] [-mps] [-W] [-delay <Time in Minutes>] [-bc <color>]\n");
1007 printf(" [-lc <color>] [-dc <color>] [-wgc <color>] [-tc <color>]\n\n");
1008 printf("\t-display <Display>\t\tUse alternate X display.\n\n");
1009 printf("\t-h\t\t\t\tDisplay help screen.\n");
1010 printf("\n\t-station <METAR StationID>\n");
1011 printf("\t-s <METAR StationID>\tThe 4-character METAR Station ID.\n\n");
1012 printf("\t-W\t\t\t\tIf available, display WindChill instead\n");
1013 printf("\t\t\t\t\tof DewPoint Temperature.\n");
1014 printf("\t-metric\n");
1015 printf("\t-m\t\t\t\tDisplay variables in metric units.\n\n");
1016 printf("\t-kPa\t\t\t\tWhen toggled to metric display, show pressure\n");
1017 printf("\t\t\t\t\tin units of kPa.\n\n");
1018 printf("\t-hPa\t\t\t\tWhen toggled to metric display, show pressure\n");
1019 printf("\t\t\t\t\tin units of hPa.\n\n");
1020 printf("\t-mmHg\t\t\t\tWhen toggled to metric display, show pressure\n");
1021 printf("\t\t\t\t\tin units of mmHg. (This is the default for metric).\n\n");
1022 printf("\t-beaufort\t\t\tWhen toggled to metric display, show windspeed\n");
1023 printf("\t\t\t\t\ton the Beaufort scale. (default is km/h.)\n\n");
1024 printf("\t-mps\t\t\t\tWhen toggled to metric display, show windspeed\n");
1025 printf("\t\t\t\t\tin units of meters/second. (default is km/h.)\n\n");
1026 printf("\t-bc <color>\t\t\tBackground color. (#7e9e69 is a greenish LCD color).\n\n");
1027 printf("\t-lc <color>\t\t\tLabel color.\n\n");
1028 printf("\t-dc <color>\t\t\tData color.\n\n");
1029 printf("\t-wgc <color>\t\t\tGusty-wind/variable-direction color.\n\n");
1030 printf("\t-tc <color>\t\t\tStation ID and Time color.\n\n");
1031 printf("\t-delay <Time in Minutes>\tOverride time (in minutes) between updates (default\n");
1032 printf("\t\t\t\t\tis %ld minutes). (Times are approximate.)\n", DEFAULT_UPDATEDELAY/60);
1033 printf("\n\nTo find out more about the METAR/TAF system and to find the \n");
1034 printf("METAR code for your location, look at:\n\n");
1035 printf(" http://www.nws.noaa.gov/oso/oso1/oso12/metar.htm \n\n");
1036 printf("for NOAA's ""National Weather Service METAR/TAF Information"" page.\n");
1037 printf("To locate your site ID go to NOAA's ""Meteorological Station Information\nLookup"" page at:\n\n");
1038 printf(" http://www.nws.noaa.gov/oso/siteloc.shtml\n\n");
1050 * Compute the Julian Day number for the given date.
1051 * Julian Date is the number of days since noon of Jan 1 4713 B.C.
1053 double jd(ny, nm, nd, UT)
1054 int ny, nm, nd;
1055 double UT;
1057 double A, B, C, D, JD, day;
1059 day = nd + UT/24.0;
1062 if ((nm == 1) || (nm == 2)){
1063 ny = ny - 1;
1064 nm = nm + 12;
1067 if (((double)ny+nm/12.0+day/365.25)>=(1582.0+10.0/12.0+15.0/365.25)){
1068 A = ((int)(ny / 100.0));
1069 B = 2.0 - A + (int)(A/4.0);
1071 else{
1072 B = 0.0;
1074 if (ny < 0.0){
1075 C = (int)((365.25*(double)ny) - 0.75);
1077 else{
1078 C = (int)(365.25*(double)ny);
1081 D = (int)(30.6001*(double)(nm+1));
1084 JD = B + C + D + day + 1720994.5;
1085 return(JD);
1092 * This routine handles button presses.
1094 * - Left Mouse single click toggles Deg F/C for temperatures.
1095 * - Some other click event should display the full METAR report -- lots of
1096 * juicy stuff in there... Should bring up a separate window...
1100 void ButtonPressEvent(XButtonEvent *xev){
1102 char Command[80];
1105 * Process single clicks.
1107 DblClkDelay = 0;
1108 if ((xev->button == Button1) && (xev->type == ButtonPress)){
1110 if (GotFirstClick1) GotDoubleClick1 = 1;
1111 else GotFirstClick1 = 1;
1113 } else if ((xev->button == Button2) && (xev->type == ButtonPress)){
1115 if (GotFirstClick2) GotDoubleClick2 = 1;
1116 else GotFirstClick2 = 1;
1118 } else if ((xev->button == Button3) && (xev->type == ButtonPress)){
1120 if (GotFirstClick3) GotDoubleClick3 = 1;
1121 else GotFirstClick3 = 1;
1129 * We got a double click on Mouse Button1 (i.e. the left one)
1131 if (GotDoubleClick1) {
1132 GotFirstClick1 = 0;
1133 GotDoubleClick1 = 0;
1134 sprintf(Command, "xmessage -center -file %s/.wmWeatherReports/%s.TXT &", getenv("HOME"), StationID);
1135 system(Command);
1140 * We got a double click on Mouse Button2 (i.e. the left one)
1142 if (GotDoubleClick2) {
1143 GotFirstClick2 = 0;
1144 GotDoubleClick2 = 0;
1149 * We got a double click on Mouse Button3 (i.e. the left one)
1151 if (GotDoubleClick3) {
1152 GotFirstClick3 = 0;
1153 GotDoubleClick3 = 0;
1154 ForceDownload = 1;
1155 ForceUpdate = 1;
1158 return;
1167 * This routine handles key presses.
1170 void KeyPressEvent(XKeyEvent *xev){
1172 Metric = !Metric;
1176 if (Metric){
1178 switch(PressureUnits){
1179 case 0: PressureConv = 25.4;
1180 break;
1182 case 1: PressureConv = 3.38639;
1183 break;
1185 case 2: PressureConv = 33.8639;
1186 break;
1188 case 3: PressureConv = 25.4;
1189 break;
1192 } else if (!Metric){
1194 PressureConv = 1.0;
1200 ForceUpdate = 1;
1202 return;
1207 char *StringToUpper(char *String) {
1209 int i;
1211 for (i = 0; i < strlen(String); i++)
1212 String[i] = toupper(String[i]);
1214 return String;