float wvutilsCalculateAirDensity (float tempF, float bp, float dp) { float tempC = wvutilsConvertFToC (tempF); float bpMB = wvutilsConvertINHGToHPA (bp); float dewpoint = wvutilsConvertFToC (dp); float emb = getVaporPressure (dewpoint); float density = calcDensity (bpMB, emb, tempC); return density; }
// Calculate the wet bulb temperature: // Based on NOAA Java Script http://www.srh.noaa.gov/epz/?n=wxcalc_rh float wvutilsCalculateWetBulbTemp( float temp, float humidity, float pressure) { float tempC = wvutilsConvertFToC(temp); float pressureMB = wvutilsConvertINHGToHPA(pressure); float Ewguess, Eguess; float Es = 6.112 * exp(17.67 * tempC / (tempC + 243.5)); float Twguess = 0.0; float incr = 10.0; int previoussign = 1; int cursign; float Edifference = 1; float E2 = Es * (humidity/100.0); while (fabs(Edifference) > 0.05) { Ewguess = 6.112 * exp((17.67 * Twguess) / (Twguess + 243.5)); Eguess = Ewguess - pressureMB * (tempC - Twguess) * 0.00066 * (1.0 + (0.00115 * Twguess)); Edifference = E2 - Eguess; if (Edifference == 0) { break; } else { if (Edifference < 0) cursign = -1; else cursign = 1; if (cursign != previoussign) { previoussign = cursign; incr = incr/10; } } Twguess = Twguess + incr * previoussign; } return wvutilsConvertCToF(Twguess); }
// calculate altimeter pressure from station pressure float wvutilsConvertSPToAltimeter (float SPInches, float elevationFT) { double magicEXP = 0.190284; double inverseMagicEXP = 1 / magicEXP; double elevMeters = (double)wvutilsConvertFeetToMeters(elevationFT); double stationPressureMB = (double)wvutilsConvertINHGToHPA(SPInches); double constantTerm; double variableTerm; double tempdouble; double altimeter; // Formula used: http://www.wrh.noaa.gov/slc/projects/wxcalc/formulas/altimeterSetting.pdf // calculate the constant term constantTerm = pow (1013.25, magicEXP); constantTerm *= 0.0065; constantTerm /= 288; // calculate the variable term tempdouble = stationPressureMB - 0.3; tempdouble = pow (tempdouble, magicEXP); variableTerm = elevMeters / tempdouble; // compute main term tempdouble = constantTerm * variableTerm; tempdouble += 1; tempdouble = pow (tempdouble, inverseMagicEXP); // compute altimeter altimeter = stationPressureMB - 0.3; altimeter *= tempdouble; // finally, convert back to inches altimeter *= 0.0295299; return (float)altimeter; }
static void processCWOP () { RADSOCK_ID socket; time_t ntime; struct tm *gmTime; char cwopBuffer[256], login[64]; int length = 0; char *serv; int port; volatile WVIEW_MSG_ARCHIVE_NOTIFY Notify; memcpy ((void*)&Notify, (void*)&cwopWork.ArchiveMsg, sizeof(WVIEW_MSG_ARCHIVE_NOTIFY)); // format the CWOP data ntime = time (NULL); gmTime = gmtime (&ntime); length = sprintf (cwopBuffer, "%s>APRS,TCPXX*,qAX,%s:@", cwopWork.callSign, cwopWork.callSign); length += sprintf (&cwopBuffer[length], "%2.2d%2.2d%2.2dz", gmTime->tm_mday, gmTime->tm_hour, gmTime->tm_min); length += sprintf (&cwopBuffer[length], "%s/%s", cwopWork.latitude, cwopWork.longitude); // check for any wind registered if (Notify.wspeed < 0) { length += sprintf (&cwopBuffer[length], "_..."); } else { length += sprintf (&cwopBuffer[length], "_%3.3d", Notify.winddir); } length += sprintf (&cwopBuffer[length], "/%3.3d", Notify.wspeed); length += sprintf (&cwopBuffer[length], "g%3.3d", Notify.hiwspeed); if (Notify.temp < 0) { if (((Notify.temp * (-1)) % 10) >= 5) { Notify.temp -= 10; } length += sprintf (&cwopBuffer[length], "t-%2.2d", (Notify.temp * (-1))/10); } else { if ((Notify.temp % 10) >= 5) { Notify.temp += 10; } length += sprintf (&cwopBuffer[length], "t%3.3d", Notify.temp/10); } length += sprintf (&cwopBuffer[length], "P%3.3d", Notify.rainDay); if (Notify.humidity >= 0 && Notify.humidity <= 100) { length += sprintf (&cwopBuffer[length], "h%2.2d", Notify.humidity % 100); } length += sprintf (&cwopBuffer[length], "b%5.5d", (int)(10 * wvutilsConvertINHGToHPA((float)Notify.altimeter/1000.0))); sprintf (&cwopBuffer[length], ".%s", wvutilsCreateCWOPVersion(globalWviewVersionStr)); // connect to the CWOP server - try the primary then secondary then tertiary socket = radSocketClientCreate (cwopWork.server1, cwopWork.portNo1); if (socket == NULL) { statusUpdateMessage("CWOP-connect: failed to connect to server"); statusIncrementStat(CWOP_STATS_CONNECT_ERRORS); wvutilsLogEvent (PRI_MEDIUM, "CWOP-connect: failed to connect to %s:%d", cwopWork.server1, cwopWork.portNo1); // try the secondary server socket = radSocketClientCreate (cwopWork.server2, cwopWork.portNo2); if (socket == NULL) { statusUpdateMessage("CWOP-connect: failed to connect to server"); statusIncrementStat(CWOP_STATS_CONNECT_ERRORS); wvutilsLogEvent (PRI_MEDIUM, "CWOP-connect: failed to connect to %s:%d", cwopWork.server2, cwopWork.portNo2); // try the tertiary server socket = radSocketClientCreate (cwopWork.server3, cwopWork.portNo3); if (socket == NULL) { // we are all out of luck this time! statusUpdateMessage("CWOP-connect: failed to connect to server"); statusIncrementStat(CWOP_STATS_CONNECT_ERRORS); wvutilsLogEvent (PRI_MEDIUM, "CWOP-connect: failed to connect to %s:%d", cwopWork.server3, cwopWork.portNo3); radMsgLog (PRI_HIGH, "CWOP-connect: failed to connect to all 3 APRS servers!"); return; } else { serv = cwopWork.server3; port = cwopWork.portNo3; } } else { serv = cwopWork.server2; port = cwopWork.portNo2; } } else { serv = cwopWork.server1; port = cwopWork.portNo1; } // wait 1 second ... radUtilsSleep (1000); // transmit the data sprintf (login, "user %6s pass %d vers %s", cwopWork.callSign, (int)getPasscode(cwopWork.callSign), globalWviewVersionStr); length = strlen (login); login[length] = 0x0D; // tack on the CR and LF login[length+1] = 0x0A; login[length+2] = 0; if (radSocketWriteExact (socket, login, length + 2) != (length + 2)) { statusUpdateMessage("CWOP-error: failed to login to server"); radMsgLog (PRI_HIGH, "CWOP-error: %d: failed to login to %s:%d!", errno, serv, port); radSocketDestroy (socket); return; } // wait 3 seconds ... radUtilsSleep (3000); // write the data record wvutilsLogEvent (PRI_STATUS, "CWOP-send: %s", cwopBuffer); length = strlen (cwopBuffer); cwopBuffer[length] = 0x0D; // tack on the CR and LF cwopBuffer[length+1] = 0x0A; cwopBuffer[length+2] = 0; if (radSocketWriteExact (socket, cwopBuffer, length + 2) != (length + 2)) { statusUpdateMessage("CWOP-error: failed to write to server"); radMsgLog (PRI_HIGH, "CWOP-error: %d: failed to write to %s:%d!", errno, serv, port); radSocketDestroy (socket); return; } statusIncrementStat(CWOP_STATS_PKTS_SENT); // wait 3 more seconds ... radUtilsSleep (3000); // close connection and cleanup radSocketDestroy (socket); return; }
static void processAlarms (LOOP_PKT *loopData) { WVIEW_ALARM *alarm; float tempFloat; // process the local alarms: for (alarm = (WVIEW_ALARM *) radListGetFirst (&alarmsWork.alarmList); alarm != NULL; alarm = (WVIEW_ALARM *) radListGetNext (&alarmsWork.alarmList, (NODE_PTR)alarm)) { // first check to see if we are in abatement if (alarm->triggered) { if ((radTimeGetSECSinceEpoch () - alarm->abateStart) < alarm->abateSecs) { // abatement - go to the next alarm continue; } else { // clear trigger for future alarms alarm->triggered = FALSE; } } // switch on alarm type switch (alarm->type) { case Barometer: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertINHGToHPA(loopData->barometer); } else { tempFloat = loopData->barometer; } break; case InsideTemp: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->inTemp); } else { tempFloat = loopData->inTemp; } break; case InsideHumidity: tempFloat = (float)loopData->inHumidity; break; case OutsideTemp: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->outTemp); } else { tempFloat = loopData->outTemp; } break; case WindSpeed: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertMPHToKPH((float)loopData->windSpeed); } else { tempFloat = (float)loopData->windSpeed; } break; case TenMinuteAvgWindSpeed: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertMPHToKPH((float)loopData->tenMinuteAvgWindSpeed); } else { tempFloat = (float)loopData->tenMinuteAvgWindSpeed; } break; case WindDirection: tempFloat = (float)loopData->windDir; break; case OutsideHumidity: tempFloat = (float)loopData->outHumidity; break; case RainRate: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertRainINToMetric(loopData->rainRate); } else { tempFloat = loopData->rainRate; } break; case StormRain: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertRainINToMetric(loopData->stormRain); } else { tempFloat = loopData->stormRain; } break; case DayRain: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertRainINToMetric(loopData->dayRain); } else { tempFloat = loopData->dayRain; } break; case MonthRain: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertRainINToMetric(loopData->monthRain); } else { tempFloat = loopData->monthRain; } break; case YearRain: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertRainINToMetric(loopData->yearRain); } else { tempFloat = loopData->yearRain; } break; case TxBatteryStatus: tempFloat = (float)loopData->txBatteryStatus; break; case ConsoleBatteryVoltage: tempFloat = (((float)loopData->consBatteryVoltage * 300)/512)/100; break; case DewPoint: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->dewpoint); } else { tempFloat = loopData->dewpoint; } break; case WindChill: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->windchill); } else { tempFloat = loopData->windchill; } break; case HeatIndex: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->heatindex); } else { tempFloat = loopData->heatindex; } break; case Radiation: tempFloat = (float)loopData->radiation; break; case UV: tempFloat = (float)loopData->UV; break; case ET: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertRainINToMetric(loopData->dayET); } else { tempFloat = loopData->dayET; } break; case ExtraTemp1: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->extraTemp1); } else { tempFloat = loopData->extraTemp1; } break; case ExtraTemp2: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->extraTemp2); } else { tempFloat = loopData->extraTemp2; } break; case ExtraTemp3: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->extraTemp3); } else { tempFloat = loopData->extraTemp3; } break; case SoilTemp1: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->soilTemp1); } else { tempFloat = loopData->soilTemp1; } break; case SoilTemp2: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->soilTemp2); } else { tempFloat = loopData->soilTemp2; } break; case SoilTemp3: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->soilTemp3); } else { tempFloat = loopData->soilTemp3; } break; case SoilTemp4: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->soilTemp4); } else { tempFloat = loopData->soilTemp4; } break; case LeafTemp1: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->leafTemp1); } else { tempFloat = loopData->leafTemp1; } break; case LeafTemp2: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->leafTemp2); } else { tempFloat = loopData->leafTemp2; } break; case ExtraHumid1: tempFloat = (float)loopData->extraHumid1; break; case ExtraHumid2: tempFloat = (float)loopData->extraHumid2; break; case Wxt510Hail: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertRainINToMetric(loopData->wxt510Hail); } else { tempFloat = loopData->wxt510Hail; } break; case Wxt510Hailrate: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertRainINToMetric(loopData->wxt510Hailrate); } else { tempFloat = loopData->wxt510Hailrate; } break; case Wxt510HeatingTemp: if (alarmsWork.isMetric) { tempFloat = wvutilsConvertFToC(loopData->wxt510HeatingTemp); } else { tempFloat = loopData->wxt510HeatingTemp; } break; case Wxt510HeatingVoltage: tempFloat = loopData->wxt510HeatingVoltage; break; case Wxt510SupplyVoltage: tempFloat = loopData->wxt510SupplyVoltage; break; case Wxt510ReferenceVoltage: tempFloat = loopData->wxt510ReferenceVoltage; break; default: // no match, blow it off continue; } // see if we tripped the breaker here if (alarm->isMax) { if (tempFloat >= alarm->bound) { // we did! alarm->triggered = TRUE; alarm->triggerValue = tempFloat; alarm->abateStart = radTimeGetSECSinceEpoch (); // run user script here statusIncrementStat(ALARM_STATS_SCRIPTS_RUN); if (executeScript (alarm) != 0) { radMsgLog (PRI_MEDIUM, "processAlarms: script %s failed", alarm->scriptToRun); } } } else { if (tempFloat <= alarm->bound) { // we did! alarm->triggered = TRUE; alarm->triggerValue = tempFloat; alarm->abateStart = radTimeGetSECSinceEpoch (); // run user script here statusIncrementStat(ALARM_STATS_SCRIPTS_RUN); if (executeScript (alarm) != 0) { radMsgLog (PRI_MEDIUM, "processAlarms: script %s failed", alarm->scriptToRun); } } } } return; }