/* open2300 - up2300.c * * Version 1.11 * * Upload WS2300 weather station data to various receivers. * The goals of this application are as follows: * * - Upload to multiple receivers in one invocation. This allows for * one schedule ( cron ) to service all receivers. * - This application is initially a refactor of wu2300 and cw2300. It * combines the efforts of those two applications. * It should be backwards compatible with those applications. * wu2300 and cw2300 could potentially call through to this application * with the proper switches. * - Common interactions with the weather station are not duplicated * for various receivers, increasing combined performance. * - Gust support for all receivers, with the gust reset occuring once for * all uploads. This was not possible with split uploads. * * This class currently supports sending data to: * * - Weather Underground * - Citizen Weather Observer Program ( CWOP ) * * Copyright 2004-2006, Kenneth Lavrsen/Robert Rice * This program is published under the GNU General Public license */ #define DEBUG 0 // wu2300 stops writing to standard out if setting this to 0 #define GUST 1 // report wind gust information (resets wind min/max) #define UPDATE 1 // wu2300 won't update weather station or receivers if set to 0 #include "rw2300.h" struct station_data { double wind_speed; double wind_direction; double wind_gust; double rain_hour; double rain_day; double temperature; double dewpoint; int humidity; double pressure; }; void process_args( int argc, char * argv[] ); void initialize_station( char * path ); void retrieve_station_data( struct station_data * ); void print_station_data( struct station_data * ); void finalize_station( void ); int upload_station_data_wu( struct station_data * ); int upload_station_data_cw( struct station_data * ); void print_usage( ); /********** MAIN PROGRAM ************************************************ * * This program reads all current weather data from a WS2300 * and sends it to Weather Underground and/or Citizens Weather * Observer Program (CWOP). * * usage: up2300 [--debug] [--noupdate] [--nogust] [--receivers=wu,cw] [config] * * --debug, turn on useful debugging information. optional, defaults to silent. * --noupdate, run in "safe" mode. will not reset the station or write to receivers. * especially useful when combined with --debug. optional, defaults to update. * --nogust, turn off gust support. optional, defaults to on. * --receivers=LIST, specify a list of receivers for data upload. * can be any of; wu,cw,all,none for Weather Underground, CWOP, all * or none respectively. optional, defaults to all. * -h or --usage, print this message then exit. * config, path to configuration file. optional, will look at default paths. * ***********************************************************************/ WEATHERSTATION ws2300; struct config_type config; struct station_data sae; int debug = DEBUG; int gust = GUST; int update = UPDATE; char receivers[50] = "all"; char * path; int main(int argc, char *argv[]) { process_args( argc, argv ); initialize_station( path ); retrieve_station_data( &sae ); if ( debug ) { print_station_data( &sae ); } finalize_station( ); if ( strstr( receivers, "all" ) != NULL || strstr( receivers, "wu" ) != NULL ) { upload_station_data_wu( &sae ); } else if ( debug ) { printf( "Upload to Weather Underground disabled.\n" ); } if ( strstr( receivers, "all" ) != NULL || strstr( receivers, "cw" ) != NULL ) { upload_station_data_cw( &sae ); } else if ( debug ) { printf( "Upload to CWOP disabled.\n" ); } return(0); } void process_args( int argc, char * argv[] ) { int i; char * param; for ( i = 1; i < argc; i++ ) { param = argv[i]; if ( strncmp(param, "--debug", 7) == 0 ) { debug = 1; } else if ( strncmp(param, "--nogust", 8) == 0 ) { gust = 0; } else if ( strncmp(param, "--noupdate", 10) == 0 ) { update = 0; } else if ( strncmp(param, "--receivers=", 12) == 0 ) { param += 12; sprintf( receivers, "%s", param ); } else if ( ( strncmp(param, "--usage", 7) == 0 ) || ( strncmp(param, "-h", 2) == 0 ) ) { print_usage( ); exit(1); } else { path = param; } } } void initialize_station( char * path ) { if ( debug ) { printf( "Initializing station.\n" ); } get_configuration(&config, path); ws2300 = open_weatherstation(config.serial_device_name); } void retrieve_station_data( struct station_data * current ) { if ( debug ) { printf( "Retrieving station data.\n" ); } /** current reading is in sae units */ current->wind_speed = wind_current( ws2300, MILES_PER_HOUR, ¤t->wind_direction ); current->wind_gust = wind_minmax(ws2300, MILES_PER_HOUR, NULL, NULL, NULL, NULL); current->rain_hour = rain_1h(ws2300, INCHES); current->rain_day = rain_24h(ws2300, INCHES); current->temperature = temperature_outdoor(ws2300, FAHRENHEIT); current->dewpoint = dewpoint(ws2300, FAHRENHEIT); current->humidity = humidity_outdoor(ws2300); current->pressure = rel_pressure(ws2300, INCHES_HG); } void print_station_data( struct station_data * current ) { printf( "Station data:\n" ); printf( "\twind speed/direction = %.1fmph/%.1fdegrees\n", current->wind_speed, current->wind_direction ); printf( "\twind gust = %.1fmph\n", current->wind_gust ); printf( "\train hour/day= %.2fin/%.2fin\n", current->rain_hour, current->rain_day ); printf( "\ttemperature = %.2ff\n", current->temperature ); printf( "\tdewpoint = %.2ff\n", current->dewpoint ); printf( "\thumidity = %d%%\n", current->humidity ); printf( "\tpressure = %.3fin\n", current->pressure ); } void finalize_station( void ) { /* Reset minimum and maximum wind readings if reporting gusts */ if ( gust ) { if ( debug ) { printf( "Gust support, resetting wind min/max.\n" ); } if ( update ) { wind_reset(ws2300, RESET_MIN + RESET_MAX); } else { if ( debug ) { printf( "Station reset disabled.\n" ); } } } else { if ( debug ) { printf( "Gust support disabled.\n" ); } } if ( debug ) { printf( "Closing station.\n" ); } close_weatherstation( ws2300 ); } int upload_station_data_wu( struct station_data * current ) { char datastring[3000] = ""; char datestring[50]; //used to hold the date stamp for the log file time_t basictime; char guststring[20] = ""; int rcode = 0; /* GET DATE AND TIME FOR the WX record in UTC */ time(&basictime); basictime = basictime - atof(config.timezone) * 60 * 60; strftime(datestring, sizeof(datestring), "&dateutc=%Y-%m-%d+%H%%3A%M%%3A%S", localtime(&basictime)); /* BUILD THE DATA STRING, START WITH URL, ID AND PASSWORD */ sprintf(datastring, "GET %s?ID=%s&PASSWORD=%s%s", WEATHER_UNDERGROUND_PATH, config.weather_underground_id, config.weather_underground_password, datestring); /* WIND GUST */ /* This requires that you reset the station regularly */ if ( gust ) { sprintf( guststring, "&windgustmph=%.2f", current->wind_gust ); } /** STATION DATA */ sprintf( datastring, "%s&tempf=%.2f&dewptf=%.2f&humidity=%d&windspeedmph=%.2f&winddir=%.1f%s" "&rainin=%.2f&dailyrainin=%.2f&baromin=%.3f", datastring, current->temperature, current->dewpoint, current->humidity, current->wind_speed, current->wind_direction, guststring, current->rain_hour, current->rain_day, current->pressure ); /* ADD SOFTWARE TYPE AND ACTION */ sprintf( datastring, "%s&softwaretype=open2300-%s&action=updateraw" " HTTP/1.0\r\nUser-Agent: open2300/%s\r\nAccept: */*\r\n" "Host: %s\r\nConnection: Keep-Alive\r\n\r\n" , datastring, VERSION, VERSION, WEATHER_UNDERGROUND_BASEURL ); if ( debug ) { printf( "Uploading to Weather Underground.\n" ); printf( "%s\n", datastring ); } /* CONNECT TO SERVER AND SEND THE RECORD */ if ( update ) { if ( ( rcode = http_request_url(datastring) ) != 0 ) { perror( "Could not send data to Weather Underground!\n" ); } } else { if ( debug ) { printf( "Data upload to Weather Underground disabled.\n" ); } } return rcode; } int upload_station_data_cw( struct station_data * current ) { char datastring[3000] = ""; char datestring[50]; //used to hold the date stamp for the log file time_t basictime; char guststring[20] = ""; int rcode = 0; /* GET DATE AND TIME FOR the WX record in UTC */ time(&basictime); basictime = basictime - atof(config.timezone) * 60 * 60; strftime(datestring, sizeof(datestring), "@%d%H%Mz",localtime(&basictime)); /* BUILD THE DATA STRING, START WITH URL, ID AND PASSWORD */ sprintf(datastring, "%s>APRS,TCPXX*,qAX,%s:%s%s/%s", config.citizen_weather_id, config.citizen_weather_id, // Build weather record datestring, // Add date time config.citizen_weather_latitude, config.citizen_weather_longitude); // Add Lat Lon /* WIND GUST */ /* This requires that you reset the station regularly */ if ( gust ) { sprintf( guststring, "g%03.0f", current->wind_gust ); } /** STATION DATA */ sprintf( datastring, "%s_%03.0f/%03.0f%st%03.0fr%03.0fp%03.0fh%02db%05.0f", datastring, current->wind_direction, current->wind_speed, guststring, current->temperature, current->rain_hour * 100, // hundredths of an inch current->rain_day * 100, // hundredths of an inch current->humidity, current->pressure * ( INCHES_HG / MILLIBARS ) * 10 ); // tenths of millibars /* ADD SOFTWARE TYPE AND ACTION */ sprintf( datastring, "%s.open2300v%s", datastring, VERSION ); if ( debug ) { printf( "Uploading to CWOP.\n" ); printf( "%s\n", datastring ); } /* CONNECT TO SERVER AND SEND THE RECORD */ if ( update ) { if ( ( rcode = citizen_weather_send(&config, datastring) ) != 0 ) { perror( "Could not send data to Citizen Weather!\n" ); } } else { if ( debug ) { printf( "Data upload to CWOP disabled.\n" ); } } return rcode; } void print_usage( ) { printf( "\nThis program reads all current weather data from a WS2300 and sends it to\n"); printf( "Weather Underground and/or Citizens Weather Observer Program (CWOP).\n\n"); printf( "usage: up2300 [--debug] [--noupdate] [--nogust] [--receivers=wu,cw] [config]\n\n"); printf( " --debug, turn on useful debugging information. optional, defaults to silent.\n\n"); printf( " --noupdate, run in \"safe\" mode. will not reset the station or write to\n"); printf( " data receivers. especially useful when combined with --debug. \n"); printf( " optional, defaults to update.\n\n"); printf( " --nogust, turn off gust support. optional, defaults to on.\n\n"); printf( " --receivers=LIST, specify a list of receivers for data upload.\n"); printf( " can be any of; wu,cw,all,none for Weather Underground, CWOP, all\n"); printf( " or none respectively. optional, defaults to all.\n\n"); printf( " config, path to configuration file. optional, will look at default paths.\n\n"); printf( " -h or --usage, print this message then exit.\n\n"); }